使用复合文字对静态数组进行条件初始化
#include <stdint.h>
#define INIT_UINT32 1
#define INIT_INT32 2
#define INIT INIT_INT32
typedef union
{
uint32_t a;
int32_t b;
} Foo_t;
/* Why does this compile... */
static Foo_t foo_static = INIT == INIT_INT32 ?
(Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX };
/* but this doesn't? */
static Foo_t foo_static_array[] =
{
INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
};
int main(void)
{
}
编译时,使用复合文字的 foo_static 条件初始化成功,但使用复合文字的 foo_static_array 条件初始化失败。以下是编译错误。
$ gcc test.c
test.c:4:21: error: initializer element is not constant
4 | #define INIT_INT32 2
| ^
test.c:6:14: note: in expansion of macro ‘INIT_INT32’
6 | #define INIT INIT_INT32
| ^~~~~~~~~~
test.c:21:3: note: in expansion of macro ‘INIT’
21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
| ^~~~
test.c:4:21: note: (near initialization for ‘foo_static_array[0]’)
4 | #define INIT_INT32 2
| ^
test.c:6:14: note: in expansion of macro ‘INIT_INT32’
6 | #define INIT INIT_INT32
| ^~~~~~~~~~
test.c:21:3: note: in expansion of macro ‘INIT’
21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
| ^~~~
谁能解释为什么会这样?
#include <stdint.h>
#define INIT_UINT32 1
#define INIT_INT32 2
#define INIT INIT_INT32
typedef union
{
uint32_t a;
int32_t b;
} Foo_t;
/* Why does this compile... */
static Foo_t foo_static = INIT == INIT_INT32 ?
(Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX };
/* but this doesn't? */
static Foo_t foo_static_array[] =
{
INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
};
int main(void)
{
}
When compiled, the conditional initialization of foo_static using compound literals succeeds, but the conditional initialization of foo_static_array using compound literals fails. Following are the compile errors.
$ gcc test.c
test.c:4:21: error: initializer element is not constant
4 | #define INIT_INT32 2
| ^
test.c:6:14: note: in expansion of macro ‘INIT_INT32’
6 | #define INIT INIT_INT32
| ^~~~~~~~~~
test.c:21:3: note: in expansion of macro ‘INIT’
21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
| ^~~~
test.c:4:21: note: (near initialization for ‘foo_static_array[0]’)
4 | #define INIT_INT32 2
| ^
test.c:6:14: note: in expansion of macro ‘INIT_INT32’
6 | #define INIT INIT_INT32
| ^~~~~~~~~~
test.c:21:3: note: in expansion of macro ‘INIT’
21 | INIT == INIT_INT32 ? (Foo_t){ .a = UINT32_MAX} : (Foo_t){ .b = INT32_MAX }
| ^~~~
Can anyone explain why this is the case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
GCC 提供前一种初始化作为 C 标准的扩展。它没有提供后者。这是 GCC 的选择,不是标准强制要求的。对于
-pedantic
,GCC 抱怨两者。C标准中的相关段落是C 2018 6.7.9 4:
这是在 Constraints 部分中,这意味着符合要求的编译器必须对其进行诊断,就像使用
-pedantic
时 GCC 所做的那样,尽管它仍然接受代码并完成编译。如果没有-pedantic
,GCC 接受两者,但仅诊断后者。关于 C 扩展的 GCC 文档没有提及造成这种差异的原因。它的 条款 6.27 表示具有自动存储持续时间的聚合的初始值设定项不是要求是常量表达式,但 C 扩展子句中没有子子句来处理静态对象的初始值设定项。
为了使您的代码严格符合要求,您不应在非数组或数组初始化中使用这些初始值设定项。
GCC is providing the former initialization as an extension to the C standard. It is not providing the latter. This is a GCC choice, not mandated by the standard. With
-pedantic
, GCC complains about both.The relevant passage in the C standard is C 2018 6.7.9 4:
This is in a Constraints section, which means a conforming compiler must diagnose it, as GCC does when
-pedantic
is used, although it still accepts the code and completes compilation. Without-pedantic
, GCC accepts both but only diagnoses the latter.The GCC documentation on C extensions is silent about the reason for this difference. Its clause 6.27 says that initializers for aggregates with automatic storage duration are not required to be constant expressions, but there is no subclause in the C extensions clause that addresses initializers for static objects.
To make your code strictly conforming, you should not use these initializers in either the non-array or the array initialization.