C99引入了结构指定的初始化器的概念.例如,给定:
typedef struct {
int c;
char a;
float b;
} X;
Run Code Online (Sandbox Code Playgroud)
我可以初始化为:X foo = {.a = '\1', .b = 2.0F, .c = 4};并且调用:printf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);将输出:
c = 4
a = 1
b = 2.000000
这里提到这有分配给的"令人惊讶的行为" c,然后a再b独立我指定的初始的顺序.
如果我有这样的函数,这将成为一个真正的问题:
int i = 0;
int f() {
return ++i;
}
int g() {
i += 2;
return i;
}
int h() {
i += 4; …Run Code Online (Sandbox Code Playgroud) 可以designated initializers如下所示使用(对于“ billy”),而不会出现问题,但是当对动态内存使用相同的初始化方法时,在编译时,东西会中断。
使用指定的初始值设定项有哪些限制?
除了我们要写入的位置(即地址)以外,还有什么使这两个初始化不同?为什么我们不能在动态内存中使用指定的初始化程序?
struct student{
char *name;
int age;
};
void print_student(struct student* st){
printf("Student: %s is %d years old\n", st->name, st->age);
}
int main(void) {
srand(time(NULL));
struct student *molly_ptr = malloc(sizeof(struct student));
struct student billy = {
.name = "billy",
.age = rand()%30
};
*molly_ptr = {
.name = "molly",
.age = 25
};
//molly_ptr->name = "molly";
//molly_ptr->age = 25;
print_student(&billy);
print_student(molly_ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
error: expected expression before '{' token
*molly_ptr = …Run Code Online (Sandbox Code Playgroud) 为什么在使用复合文字(示例代码中的情况 b)定义结构后可以分配结构,而数组不能(情况 c))?
我知道情况 a) 不起作用,因为当时编译器不知道分配的 rhs 上的内存布局。它可以是任何类型的演员表。但是按照这条线,在我看来,c) 是一个完美定义的情况。
typedef struct MyStruct {
int a, b, c;
} MyStruct_t;
void function(void) {
MyStruct_t st;
int arr[3];
// a) Invalid
st = {.a=1, .b=2, .c=3};
// b) Valid since C90
st = (MyStruct_t){.a=1, .b=2, .c=3};
// c) Invalid
arr = (int[3]){[0]=1, [1]=2, [2]=3};
}
Run Code Online (Sandbox Code Playgroud)
编辑:我知道我不能分配给一个数组 - 这是 C 的设计方式。我可以使用 memcpy 或单独分配值。
阅读下面的评论和答案后,我想现在我的问题分解为一个永远争论不休的难题,即为什么不能分配给数组。
更令人费解的是,正如这篇文章和下面MM的评论所建议的那样,以下分配是完全有效的(当然,它违反了严格的别名规则)。您可以将数组包装在结构中并进行一些讨厌的转换来模拟可分配的数组。
typedef struct Arr3 {
int a[3];
} Arr3_t;
void function(void) {
Arr3_t a; …Run Code Online (Sandbox Code Playgroud) 我在 Vulkan 教程中看到了以下代码:
VkImageMemoryBarrier imageMemoryBarrier = {
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
/* .image and .subresourceRange should identify image subresource accessed */
};
Run Code Online (Sandbox Code Playgroud)
如果我只列出了没有成员 '.member_name =' 的枚举,那将是聚合初始化,对吗?但这叫什么?这个类在 .srcAccreasMask 之前还有其他成员,我假设所有其他没有提到的成员都是零初始化的?但是如果我不知道它叫什么,就很难查到它。另外,我记得像这样的东西是一个新的 C 特性,但它在 Visual Studio 中为我用 C++ 编译。这是一个 C++ 特性,对吧?
c c++ initialization designated-initializer aggregate-initialization
我有一些有效的代码,但我不明白为什么。这是有问题的代码:
struct SceneInterface *TitleAsScene = &(struct SceneInterface) {
.update = (void (*)(void *)) title_update,
.render = (void (*)(void *)) title_render,
};
Run Code Online (Sandbox Code Playgroud)
我得到了函数指针和指定的初始值设定项,但是&(struct SceneInterface)部分在做什么?通常它表示address of,但是括号中的东西是一个类型,而不是一个变量,那么它指向的是什么?如果它返回一个指向 struct SceneInterface 的指针,那么左侧已经是那个,所以我不明白为什么需要它,以及为什么如果我删除它会出现分段错误。
这是完整的工作代码供参考:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct SceneInterface {
void (*update)(void *instance);
void (*render)(void *instance);
};
struct Scene {
void *instance;
const struct SceneInterface *interface;
};
struct Scene *scene_create(void *instance, struct SceneInterface *interface)
{
struct Scene *scene = (struct Scene *) malloc(sizeof(struct Scene));
scene->instance = instance;
scene->interface = interface;
return …Run Code Online (Sandbox Code Playgroud) 被认为基本上总是使用指定的初始化程序,我觉得创建新的viewInstances [UIView new];而不是[[UIView alloc] initWithFrame:CGRectZero];?
有没有理由不这样做?有什么实际的区别吗?如果你正在创建一个没有任何框架信息的新视图实例,那么回退就不会[UIView new];简单地删除大量的代码错误吗?我的猜测将是[[UIView alloc] initWithFrame:CGRectZero];实际上是引擎盖下反正叫(?)
我有一个子类NSTextView,在这个子类的初始化器中,我想调用:
super.init(frame: NSMakeRect(...))
Run Code Online (Sandbox Code Playgroud)
这就是我在以NSTextView编程方式初始化时总是做的事情。我简单地写:
let textView = NSTextView(frame: NSMakeRect(0,0,10,10))
Run Code Online (Sandbox Code Playgroud)
但是,当我在子类 ( super.init(frame: (...))) 中执行此操作时,编译器会抛出错误。它不会让我使用,init(frame:)因为它init(frame:)是 的便利初始化程序NSTextView,我必须调用“超类的指定初始化程序”。
查了文档,发现是的指定构造器NSTextView是init(frame: textContainer:)但是我不想处理NSTextContainers. 为什么我必须从对象的子类调用指定的初始化程序,但如果对象没有被子类化,我可以调用便利初始化程序?每当我通常初始化 anNSTextView我不必提供 an NSTextContainer,但是当我将 an 初始化NSTextView为子类的超类时,我会这样做。为什么是这样?
另外,有没有办法NSTextView用一种“默认”文本容器来初始化?不管指定的初始值设定项如何,我在这里要做的就是创建一个NSTextView不用担心NSTextContainers.
initialization designated-initializer convenience-methods swift
这是受到这篇文章的启发,其中 不支持非平凡的指定初始化程序。
我已经阅读了这篇文章,一些答案声称已经支持此功能。
但是,使用 C++17 和此代码:
struct s {
int a[2];
s (int b): a{[1]=b} {} // error
};
s foo(1);
Run Code Online (Sandbox Code Playgroud)
我仍然收到错误:
抱歉,未实现:不支持非平凡的指定初始值设定项
s (int b): a{[1]=b} {}
我在想这个功能真的很有帮助。
所以我的问题:
是否有计划在未来的 C++ 版本(C++17 后)中支持它?
编译器
GNU C++17 - 检查魔杖盒
我正在关注"C Primer Plus"一书并遇到这样一段代码:
// designate.c -- use designated initializers
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31, 28, [4] = 31, 30, 31, [1] = 29};
int i;
for (i = 0; i < MONTHS; i++)
printf("%2d %d\n", i+1, days[i]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它在编译时报告错误:
$ cc designate.c
designate.c:6:57: warning: initializer overrides prior initialization of this subobject [-Winitializer-overrides]
int days[MONTHS] = {31, 28, [4] = 31, 30, 31, [1] = 29};
^~
designate.c:6:29: note: previous initialization is …Run Code Online (Sandbox Code Playgroud) 我认为指定的初始化程序在C++中已经停止,并且仅在C中工作.但是,我遇到了一个简单的例子,它使用clang ++进行编译和工作.
int main()
{
int a[6] = { [4] = 29, [2] = 15 };
}
Run Code Online (Sandbox Code Playgroud)
g ++:https://rextester.com/AXIZ79197(错误)
clang ++:https://rextester.com/UYVHHP56966(作品)
vc ++:https://rextester.com/UCBEU10658(错误)
g ++和vc ++都无法编译,而clang ++工作正常.值得一提的是,g ++和vc ++给出了不同的错误消息.vc ++将指定的初始值设定项与lambda表达式混淆.我想我可以将此归结为g ++是一个较旧的编译器,但我不确定.
问题: