用花括号常量初始化 `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++。该项目在 gccg++ 中编译良好,但 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,此处不适用。)