【发布时间】:2021-01-02 17:51:56
【问题描述】:
GCC 和 Clang 都允许指定的初始化程序引用正在初始化的结构或数组的成员,但这是合法且定义明确的行为吗?
以下代码示例为 GCC 和 Clang 编译和运行,并在两种情况下输出 { .a = 3, .b = 6, }:
#include <stdio.h>
typedef struct
{
int a;
int b;
} foo;
int main()
{
foo bar = {
.a = 3,
.b = bar.a + 3,
};
printf("{ .a = %d, .b = %d, }\n", bar.a, bar.b);
return 0;
}
GCC 为指定的初始化生成以下输出 (Compiler Explorer link),表明此示例的操作是安全的:
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 16], 3
mov eax, dword ptr [rbp - 16]
add eax, 3
mov dword ptr [rbp - 12], eax
draft C99 spec 的第 6.7.8 节讨论了这一点,但我不明白它是如何定义这种行为的。
特别是,第 19 点表明初始化以指定的顺序发生,但第 23 点提到了具有未指定顺序的副作用。我不确定写入结构的数据是否被视为副作用。
- 初始化应按初始化程序列表顺序进行,为特定子对象提供的每个初始化程序都将覆盖同一子对象的任何先前列出的初始化程序;所有未显式初始化的子对象都应隐式初始化,与具有静态存储持续时间的对象相同。
- 未指定初始化列表表达式中任何副作用发生的顺序
【问题讨论】:
-
你为什么对C99特别感兴趣?
-
请注意,将
bar.a初始化为 3 并不是.a = 3的副作用,因为这不是赋值操作(有副作用);它是初始化语法的一部分。 -
@JensGustedt 我想选择在 Windows 上使用 MSVC 进行跨平台项目(尽管我看到了 C11 and C18 support was announced a couple days ago)。顺便说一句,我作为 C 初学者正在阅读您的书——读起来非常愉快。
标签: c initialization c99 c11 designated-initializer