为什么GCC不能处理在结构初始化器中以sizeof作为条件的三进制中的复合文字的编译时求值?

tcbh2hod  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(91)

下面的代码:

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个,代码编译正常?
5jdjgkvh

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;

相关问题