下面的代码:
struct Int {
int i;
};
const struct Int i = {sizeof(int) ? (int){1} : 0};
结果:
初始值设定项元素不是常量
(Live demo GCC)
即使这些语句在文件范围内,因此复合文字也应该被视为常量。
但是,如果:
- 我用Clang代替;或
- 将
sizeof(int)
替换为0;或 - 将
(int){1}
替换为1;或 - 该表达式用于直接初始化
int
而不是int
结构成员,如下所示:int i = sizeof(int) ? (int){1} : 0;
代码会编译得很好。
这就引出了几个问题:
- 标准C是否允许使用
sizeof()
语句与三进制一起使用,以将一个全局结构变量成员初始化为2个值中的一个,其中至少一个是复合文字,所有这些都在编译时进行? - 为什么GCC在满足上述所有3个要求时会引发错误,但如果只满足其中任意2个或1个,代码编译正常?
1条答案
按热度按时间5jdjgkvh1#
在C23之前,在gcc和clang bug报告等中有很多关于整数常量表达式组成的争论。clang总是有“任何东西和它的母亲是一个恒定的表达式”的行为,而gcc则有更多的限制,直到后来的版本,gcc突然翻转了行为,即使标准在这里没有改变。所有这一切都是由C17(以及更早的标准)6.6 §10中一个毫无帮助的、含糊不清的段落引起的:
实现可以接受其他形式的常量表达式。
这是第6.6章中唯一留下解释空间并允许像您这样的代码的部分。这意味着整数常量表达式在gcc和clang中的支持都不稳定,使用“外来”形式的常量表达式(如复合文字或
const int x = some_other_const;
)的代码是不可移植的。市场上的大多数其他编译器将给予关于不符合C的诊断消息。直到C17,整数常量表达式定义如下(C17 6.6 §6):
一个 integer constant expression 必须是integer类型,并且只能有整数常量、枚举常量、字符常量、结果是整数常量的
sizeof
表达式、_Alignof
表达式和作为转换的直接操作数的浮点常量。在即将到来的C23中,这一点发生了变化(C23 N3096草案6.6。§8强调我的):
一个 integer constant expression 必须是integer type,并且只能有integer constants,**命名的和复合的integer类型的文字常量,字符常量,.
其中“命名常数”是一个新术语,它涵盖了以下内容:
用存储类说明符
constexpr
声明并具有对象类型,所以C23将允许
(constexpr int){1}
复合文字,我们也可以可移植地做constexpr int x = 1; const int y=x;