1

考虑以下代码:

struct Foo {
   int i;
   char c;
   float f;
};

int main() {
    struct Foo f1 = { .i = 1 };
    struct Foo f2;
    f2 = (struct Foo){ .i = 1 };
}

Afaik f1 是一个使用指定初始化器部分初始化的结构体,它的所有省略字段都保证用零初始化。但是 C 标准是否保证 f1 与 f2 相同?f2 创建语法究竟是如何调用的?

4

4 回答 4

3

但是 C 标准是否保证 f1 与 f2 相同?

在 中显示的代码之后,和main的命名成员将具有相同的值。结构中的任何填充字节不一定相同。因此,比较和与可能表明它们是不同的。此外,现在很少见,但成员中的任何填充位不一定相同。f1f2f1f2memcmp(&f1, &f2, sizeof f1)

f2 创建语法究竟是如何调用的?

(struct Foo){ .i = 1 };复合文字,在 C 2018 6.5.2.5 中定义。复合文字的语法是,并且在初始化列表的末尾可能有一个逗号。函数外的复合文字具有静态存储持续时间。函数内的复合文字具有与其封闭块关联的自动存储持续时间。( type-name ) { initializer-list }

于 2021-10-01T21:21:26.433 回答
2

f2 = (struct Foo){ .i = 1 );被称为作业

它们不相同。后者理论上(或者如果您在没有优化的情况下编译)将创建生命周期与封闭范围相同的对象。该对象将在分配中使用

但在这个简单的例子中,两者都将被优化。优化编译器(如果程序更复杂)将优化复合文字,因为您不使用对它的引用,因此生成的代码在两种情况下都是相同的

附言

未经优化检查,未创建未命名对象。

main:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-12], 0
        mov     DWORD PTR [rbp-4], 0
        mov     DWORD PTR [rbp-12], 1
        mov     QWORD PTR [rbp-24], 0
        mov     DWORD PTR [rbp-16], 0
        mov     DWORD PTR [rbp-24], 1
        mov     eax, 0
        pop     rbp
        ret
于 2021-10-01T20:44:02.417 回答
2

在这个赋值语句中

f2 = (struct Foo){ .i = 1 };

使用了一个复合字面量,它创建了一个未命名的对象,该对象的struct Foo初始化方式与 object 相同f1。然后将这个类型struct Foo的未命名对象分配给 object f2

也就是说,在此语句中,又创建了一个struct Foo具有自动存储持续时间的类型的对象。

请注意,您的代码片段中有错字

f2 = (struct Foo){ .i = 1 );
                         ^^^

你需要写

f2 = (struct Foo){ .i = 1 };
                         ^^^
于 2021-10-01T20:39:14.120 回答
2

下面的作业:

struct Foo f2 = (struct Foo){ .i = 1 };

正在使用复合文字。它等效于使用匿名变量:

struct Foo _anonymous_ = { .i = 1 };
struct Foo f2 = _anonymous_;

复合文字的生命周期与在同一范围内定义的变量的生命周期相同。

此外,它允许获取文字的地址,甚至可以做一些奇怪的事情,比如给它赋值:

(int){ 0 } = 42; // valid !

实际上,局部变量没有功能差异,编译器可能会将复合文字和初始化程序与 OP 问题的上下文相同。

但是,静态对象和全局对象的初始化有所不同,因为它们必须使用常量表达式进行初始化。但是,复合文字不是常量表达式。

static struct Foo f1 = { .i = 1 };  // ok
static struct Foo f2 = (struct Foo){ .i = 1 }; // illegal
于 2021-10-01T21:20:14.930 回答