使用支撑常量初始化`atomic_int`:这是有效的C代码吗?如果是这样,为什么它不能在clang中编译?

时间:2016-07-06 20:17:59

标签: gcc clang c11

我正在将一些代码从C11移植到C ++。该项目在gccg++中编译良好,但clang拒绝编译它。违规行如下所示:

static atomic_int sem = {0};
  

src / testdir.c:27:25:错误:非法初始化程序类型'atomic_int'         (又名'_Atomic(int)')

struct container {
    volatile atomic_ullong workerThreadCount;
    struct cfgoptions *config;
    repaircmd_t *cmd;
};
Container container = {{0}, s, NULL};
  

src / testdir.c:334:25:错误:非法初始化程序类型'volatile atomic_ullong'         (又名'volatile _Atomic(unsigned long long)')

锵: clang版本3.7.0(标签/ RELEASE_370 / final)

GCC: gcc(GCC)5.3.1 20160406(Red Hat 5.3.1-6)

操作系统: Fedora 23

测试代码: https://gist.github.com/clockley/eb42964003a2e4fe6de97d5b192d61d3

P.S i = {0}或i(0)是C ++中唯一有效的初始化器,因为原子int不是两者的原始类型,只有前者是有效的C。

2 个答案:

答案 0 :(得分:3)

我相信这是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显式允许标量对象的初始值设定项括在大括号(N1570 6.7.9p11)中。我没有看到任何禁止原始对象的初始化器。

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>标题定义了一个宏ATOMIC_VAR_INIT,它用于初始化原子对象,例如:

atomic_int guide = ATOMIC_VAR_INIT(42);

对于具有自动存储持续时间的原子对象似乎是必需的,这在此处不适用。)

答案 1 :(得分:-3)

我必须与 Mad Physicist 强烈反对。大括号 {} 用于初始化聚合。单个int不是聚合。如果您愿意,可以将初始化程序放在()中,但 {} verboten 。如果您将其标注为一个条目,它将是一个聚合,如:

static atomic_int sem [1] = {0};

甚至

static atomic_int sem [] = {0};

如果你懒得计算一个整数初始值!