我正在将一些代码从C11移植到C ++。该项目在gcc
和g++
中编译良好,但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。
答案 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};
如果你懒得计算一个整数初始值!