以下代码:

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 struct 成员:int i = sizeof(int) ? (int){1} : 0;

代码将编译得很好.

这引发了几个问题:

  • 标准C是否允许使用sizeof()条语句与三元组一起使用,以在编译时将一个全局 struct 变量成员初始化为两个值中的一个,其中至少一个是复合文字?
  • 如果以上所有3个要求都满足,但如果只满足2或1,代码编译正常,为什么GCC会引发错误?

推荐答案

在C23之前,关于整数常量表达式是由什么组成的,在GCC和叮当错误报告等中有很多争论.郎朗一直以来都有这样一种行为:"任何东西,它的母亲都是一个不变的表情",而GCC则比较严格,直到后来的版本中,GCC突然改变了行为,尽管这里的标准很久没有改变了.所有这一切都是由C17(和更早的标准)6.6§10中的一个无用的、含糊的段落造成的:

实现可以接受其他形式的常量表达式.

这是第6.6章的唯一部分,为解释留下了空间,并允许像您这样的代码.这意味着整数常量表达式在GCC和clang中的支持都不稳定,使用"奇异"形式的常量表达式(如复合文字或const int x = some_other_const;)的代码是不可移植的.市场上的大多数其他编译器都会给出关于不符合C语言的诊断消息.


在C17之前,整数常量表达式定义如下(C17 6.6§6):

ANinteger constant expression应为整型,并且只能具有整型常量、枚举常量、字符常量以及结果为整型的sizeof个表达式的操作数 作为强制转换的直接操作数的常量、_Alignof表达式和浮点常量.

在即将到来的C23中,这一点发生了变化(C23 N3096草案6.6.§8强调我的观点):

integer constant expression应为整数类型,并且只能具有整数常量、named and compound literal constants of integer type、字符常量、...

其中,"命名常量"是一个新术语,其中包括以下内容:

用存储类说明符constexpr声明并且具有对象类型,

因此,C23将允许(constexpr int){1}个复合文字,我们也可以移植到constexpr int x = 1; const int y=x;

C++相关问答推荐

C/C++中的状态库

C如何显示字符串数组中的第一个字母

以c格式打印时间戳

是否有任何情况(特定类型/值),类型双关在所有符合标准的C实现中产生相同的行为?

如果实际的syscall是CLONE(),那么为什么strace接受fork()呢?

exit(EXIT_FAILURE):Tcl C API类似功能

通过管道将一个子系统的标准输出发送到另一个子系统的标准输出

丑陋的三重间接:可扩展的缓冲区管理 struct

如何使用低级C++写出数值

在C中将通用字符名称转换为UTF-8

ATmega328P EEPROM未写入

在C23中使用_GENERIC实现带有右值的IS_POINTER(P)?

获取每个循环迭代结束时的当前时间

getline()从c中的外部函数传递指针时输出null

无法访问共享目标文件内的共享指针

int * 指向int的哪个字节?

即使我在C++中空闲,也肯定会丢失内存

浮点正零何时不全为零?

macos/arm64 上地址空间不使用第一位吗?

C 中从 Unix 纪元时间转换的损坏