#include <stdint.h>\n\n#define INIT_UINT32 1\n#define INIT_INT32 2\n\n#define INIT INIT_INT32\n\ntypedef union\n{\n uint32_t a;\n int32_t b;\n} Foo_t;\n\n/* Why does this compile... */\nstatic Foo_t foo_static = INIT == INIT_INT32 ?\n (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX };\n\n/* but this doesn't? */\nstatic Foo_t foo_static_array[] =\n{\n INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }\n};\n\nint main(void)\n{\n}\nRun Code Online (Sandbox Code Playgroud)\n编译时,使用复合文字的 foo_static 条件初始化成功,但使用复合文字的 foo_static_array 条件初始化失败。以下是编译错误。
\n$ gcc test.c\ntest.c:4:21: error: initializer element is not constant\n 4 | #define INIT_INT32 2\n | ^\ntest.c:6:14: note: in expansion of macro \xe2\x80\x98INIT_INT32\xe2\x80\x99\n 6 | #define INIT INIT_INT32\n | ^~~~~~~~~~\ntest.c:21:3: note: in expansion of macro \xe2\x80\x98INIT\xe2\x80\x99\n 21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }\n | ^~~~\ntest.c:4:21: note: (near initialization for \xe2\x80\x98foo_static_array[0]\xe2\x80\x99)\n 4 | #define INIT_INT32 2\n | ^\ntest.c:6:14: note: in expansion of macro \xe2\x80\x98INIT_INT32\xe2\x80\x99\n 6 | #define INIT INIT_INT32\n | ^~~~~~~~~~\ntest.c:21:3: note: in expansion of macro \xe2\x80\x98INIT\xe2\x80\x99\n 21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }\n | ^~~~\nRun Code Online (Sandbox Code Playgroud)\n谁能解释为什么会这样?
\nGCC 提供前一种初始化作为 C 标准的扩展。它没有提供后者。这是 GCC 的选择,不是标准强制要求的。对于-pedantic,GCC 抱怨两者。
C标准中的相关段落是C 2018 6.7.9 4:
具有静态或线程存储持续时间的对象的初始值设定项中的所有表达式都应是常量表达式或字符串文字。
这是在约束部分中,这意味着符合标准的编译器必须对其进行诊断,就像 GCC 在-pedantic使用 时所做的那样,尽管它仍然接受代码并完成编译。如果没有-pedantic,GCC 接受两者,但仅诊断后者。
关于 C 扩展的 GCC 文档没有提及造成这种差异的原因。它的第 6.27 条规定,具有自动存储持续时间的聚合的初始值设定项不需要是常量表达式,但 C 扩展子句中没有子条款来解决静态对象的初始值设定项。
为了使您的代码严格符合要求,您不应在非数组或数组初始化中使用这些初始值设定项。