具有静态存储持续时间的对象的初始化程序需要由常量表达式组成。正如@EugenSh。在评论中观察到,“恒定表达”是一个定义好的术语。具体来说,在 C2011 中,它的主题是第 6.6 节 http://port70.net/~nsz/c/c11/n1570.html#6.6。描述很简单
常量表达式可以在翻译过程中求值,而不是
运行时,因此可以在常量可能出现的任何地方使用
是。
但问题在于细节。常量表达式的语义细节包含常量表达式的特定类型和使用的特定规则。
例如,表达式a
在任何情况下都不是“整数常量表达式”,无论类型或const
ness of a
,因此不能在标准要求特定类型的常量表达式的情况下使用,例如位域宽度。
尽管该标准没有给出它的名称,但它为初始化程序中的常量表达式提供了稍微宽松的规则,这就是我们在这里考虑的情况:
这样的常量表达式应为或计算为以下之一
下列的:
- 算术常量表达式,
- 空指针常量,
- 地址常量,或
- 完整对象类型的地址常量加上或减去整型常量表达式。
术语“算术常量表达式”和“地址常量”也被定义:
算术常量表达式应具有算术类型并且应
仅具有整型常量、浮点常量的操作数,
枚举常量、字符常量、sizeof 表达式
结果是整数常量,并且_Alignof
表达式。 [...]
地址常量是一个空指针,一个指向左值的指针
指定静态存储持续时间的对象,或指向
功能指示符;它应使用一元 & 显式创建
运算符或整数常量转换为指针类型,或隐式通过
使用数组或函数类型的表达式。 [...]
没有适合您的各种初始化程序b
变量符合这些规则。指定对象的左值表达式const
-限定类型不属于允许出现在标准初始化器所要求的任何常量表达式变体中的元素。
该标准通常允许
实现可以接受其他形式的常量表达式。
,但这不会覆盖其对初始值设定项中出现的常量表达式的特定要求。
每个给定的变量声明b
违反了出现在约束之外的标准的“应”要求。因此,结果行为是未定义的,但该标准不需要诊断。实现可以接受此类形式作为扩展,正如 GCC 8.2 显然所做的那样,并且 GCC 的-pedantic
选项确保仅在标准要求的情况下进行诊断,但标准不包括这些情况。
由于行为未定义,因此观察到的各种实现的行为都不是不合格的。您不能依赖一致的实现来拒绝不合格的代码。在某些情况下(但不是这些)它必须diagnose不符合规定,但即使在这种情况下,无论如何也允许成功翻译。
我搞不清楚了。这是预期的行为并且这样的代码应该编译吗?
不,但是期望它无法编译也是不安全的。
为什么/为什么不?
我在上面解释了为什么各种代码不符合要求,因此可能会被符合要求的编译器拒绝。但另一方面,符合标准的编译器不需要拒绝不符合标准的代码。
gcc7.4和gcc8.1之间有什么变化?这是编译器错误吗?这是编译器扩展吗?
海湾合作委员会显然实施了延期。我不确定这是否是故意的,但这肯定是结果。只要行为是人们天真的所期望的,它看起来就相当自然和良性,除非从 GCC(不)帮助您编写一致代码的角度来看。