用花括号常量初始化 `atomic_int`:这是有效的 C 代码吗?如果是这样,为什么它不在 clang 中编译?
Initializing an `atomic_int` with a braced constant: Is this valid C code? If so why does it not compile in clang?
我正在将一些代码从 C11 移植到 C++。该项目在 gcc
和 g++
中编译良好,但 clang
拒绝编译它。违规行如下所示:
static atomic_int sem = {0};
src/testdir.c:27:25: error: illegal initializer type 'atomic_int'
(aka '_Atomic(int)')
和
struct container {
volatile atomic_ullong workerThreadCount;
struct cfgoptions *config;
repaircmd_t *cmd;
};
Container container = {{0}, s, NULL};
src/testdir.c:334:25: error: illegal initializer type 'volatile atomic_ullong'
(aka 'volatile _Atomic(unsigned long long)')
叮当声:
clang 版本 3.7.0 (tags/RELEASE_370/final)
海湾合作委员会:
gcc (海湾合作委员会) 5.3.1 20160406 (红帽 5.3.1-6)
操作系统:
软呢帽 23
测试代码:
https://gist.github.com/clockley/eb42964003a2e4fe6de97d5b192d61d3
P.S i = {0} 或 i(0) 是 C++ 中唯一有效的初始值设定项,因为原子整数不是这两者的原始类型,只有前者是有效的 C。
我必须强烈反对疯狂物理学家。大括号 {} 用于初始化聚合。单个 int 不是聚合。如果愿意,您可以将初始化程序放在 () 中,但 {} 是 verboten。如果您将它划分为一个条目,它将是一个聚合,如:
static atomic_int sem[ 1 ] = { 0 };
甚至
static atomic_int sem[] = { 0 };
如果你懒得数一个整数初始值设定项!
我认为这是 clang 中的一个错误。
这是一个简单的测试用例,用 gcc 和 clang 编译的结果:
$ cat c.c
static _Atomic int x = ( 42 );
static _Atomic int y = { 42 };
$ gcc-6.1.0 -std=c11 -c c.c
$ clang-3.7 -std=c11 -c c.c
c.c:2:24: error: illegal initializer type '_Atomic(int)'
static _Atomic int y = { 42 };
^
1 error generated.
$
C 明确允许将标量 object 的初始值设定项括在大括号中 (N1570 6.7.9p11)。我没有看到任何禁止原子 object.
的初始值设定项
Atomics 是 C11 中的可选功能,但 gcc 和 clang 都支持它(均未预定义 __STDC_NO_ATOMICS__
)。
作为一种解决方法,我建议只放下大括号。这个:
static _Atomic int z = 42;
有效并被两个编译器接受。
如果您需要将代码编译为 C 和 C++,那么您可能需要重新考虑该要求。但如果确实有必要,可以使用__cplusplus
预定义的宏来区分C和C++编译器:
static _Atomic int foo =
#ifdef __cplusplus
{ 42 };
#else
42;
#endif
或者用宏玩一些其他的把戏。
(我会注意到 C11 的 <stdatomic.h>
header 定义了一个宏 ATOMIC_VAR_INIT
,旨在用于初始化原子 objects,例如:
atomic_int guide = ATOMIC_VAR_INIT(42);
似乎需要具有自动存储持续时间的原子 objects,此处不适用。)
我正在将一些代码从 C11 移植到 C++。该项目在 gcc
和 g++
中编译良好,但 clang
拒绝编译它。违规行如下所示:
static atomic_int sem = {0};
src/testdir.c:27:25: error: illegal initializer type 'atomic_int' (aka '_Atomic(int)')
和
struct container {
volatile atomic_ullong workerThreadCount;
struct cfgoptions *config;
repaircmd_t *cmd;
};
Container container = {{0}, s, NULL};
src/testdir.c:334:25: error: illegal initializer type 'volatile atomic_ullong' (aka 'volatile _Atomic(unsigned long long)')
叮当声: clang 版本 3.7.0 (tags/RELEASE_370/final)
海湾合作委员会: gcc (海湾合作委员会) 5.3.1 20160406 (红帽 5.3.1-6)
操作系统: 软呢帽 23
测试代码: https://gist.github.com/clockley/eb42964003a2e4fe6de97d5b192d61d3
P.S i = {0} 或 i(0) 是 C++ 中唯一有效的初始值设定项,因为原子整数不是这两者的原始类型,只有前者是有效的 C。
我必须强烈反对疯狂物理学家。大括号 {} 用于初始化聚合。单个 int 不是聚合。如果愿意,您可以将初始化程序放在 () 中,但 {} 是 verboten。如果您将它划分为一个条目,它将是一个聚合,如:
static atomic_int sem[ 1 ] = { 0 };
甚至
static atomic_int sem[] = { 0 };
如果你懒得数一个整数初始值设定项!
我认为这是 clang 中的一个错误。
这是一个简单的测试用例,用 gcc 和 clang 编译的结果:
$ cat c.c
static _Atomic int x = ( 42 );
static _Atomic int y = { 42 };
$ gcc-6.1.0 -std=c11 -c c.c
$ clang-3.7 -std=c11 -c c.c
c.c:2:24: error: illegal initializer type '_Atomic(int)'
static _Atomic int y = { 42 };
^
1 error generated.
$
C 明确允许将标量 object 的初始值设定项括在大括号中 (N1570 6.7.9p11)。我没有看到任何禁止原子 object.
的初始值设定项Atomics 是 C11 中的可选功能,但 gcc 和 clang 都支持它(均未预定义 __STDC_NO_ATOMICS__
)。
作为一种解决方法,我建议只放下大括号。这个:
static _Atomic int z = 42;
有效并被两个编译器接受。
如果您需要将代码编译为 C 和 C++,那么您可能需要重新考虑该要求。但如果确实有必要,可以使用__cplusplus
预定义的宏来区分C和C++编译器:
static _Atomic int foo =
#ifdef __cplusplus
{ 42 };
#else
42;
#endif
或者用宏玩一些其他的把戏。
(我会注意到 C11 的 <stdatomic.h>
header 定义了一个宏 ATOMIC_VAR_INIT
,旨在用于初始化原子 objects,例如:
atomic_int guide = ATOMIC_VAR_INIT(42);
似乎需要具有自动存储持续时间的原子 objects,此处不适用。)