静态数组的条件初始化,使用复合文字
conditional initialization of static arrays, using compound literals
#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 }
| ^~~~
谁能解释为什么会这样?
GCC 提供前者初始化作为 C 标准的扩展。它没有提供后者。这是 GCC 的选择,不是标准强制要求的。对于 -pedantic
,GCC 对两者都有抱怨。
C标准中的相关段落为C 2018 6.7.9 4:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
这是在约束部分,这意味着符合标准的编译器必须诊断它,就像 GCC 在使用 -pedantic
时所做的那样,尽管它仍然接受代码并完成编译。没有 -pedantic
,GCC 接受两者但只诊断后者。
关于 C 扩展的 GCC 文档没有说明造成这种差异的原因。它的 clause 6.27 表示具有自动存储持续时间的聚合的初始值设定项不需要是常量表达式,但 C 扩展子句中没有子条款解决静态对象的初始值设定项。
为了使您的代码严格符合规范,您不应在 non-array 或数组初始化中使用这些初始化程序。
#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 }
| ^~~~
谁能解释为什么会这样?
GCC 提供前者初始化作为 C 标准的扩展。它没有提供后者。这是 GCC 的选择,不是标准强制要求的。对于 -pedantic
,GCC 对两者都有抱怨。
C标准中的相关段落为C 2018 6.7.9 4:
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
这是在约束部分,这意味着符合标准的编译器必须诊断它,就像 GCC 在使用 -pedantic
时所做的那样,尽管它仍然接受代码并完成编译。没有 -pedantic
,GCC 接受两者但只诊断后者。
关于 C 扩展的 GCC 文档没有说明造成这种差异的原因。它的 clause 6.27 表示具有自动存储持续时间的聚合的初始值设定项不需要是常量表达式,但 C 扩展子句中没有子条款解决静态对象的初始值设定项。
为了使您的代码严格符合规范,您不应在 non-array 或数组初始化中使用这些初始化程序。