11

以下代码尝试在两个不同的常量上下文中对字符串文字使用数组索引:

static char x = "abcx"[3];

_Static_assert ("abcx"[3] == 'x', "...");

根据 Compiler Explorer 的判断,工具供应商之间有明确的共识,即不允许在明确需要整数常量表达式的第二种情况下执行此操作。但是,它们似乎对第一个上下文有所不同,第一个上下文只是初始化器中使用的算术常量表达式。GCC 和 Clang 作为允许这样做的实现脱颖而出。

这本身并不有趣,因为在6.6 的第 10 段中,C11/C18 确实说“实现可以接受其他形式的常量表达式”。但是,它在这种情况下很突出,因为:

  • GCC 和 Clang 都默默地接受了这一点-pedantic(真的,编译器的签名并不意味着代码符合)。构建代码是有道理的,因为它的含义很简单,但是如果他们认为这不符合要求,我会期待一个警告,并且他们可以识别(他们认为)它是否符合要求,因为......

  • 对于这两个编译器,行为最近都发生了变化——直到 3.8 之前,Clang 都会引发错误,而 GCC 直到 8.0 之前都会引发错误。这些版本分别于 2016 年和 2018 年问世。这表明更改是故意的,但我还没有找到任何一个编译器的发行说明,其中包含这个级别的详细信息。

行为变化的时机看起来与 C18 有关,但 6.6 的措辞似乎没有改变。对整数常量表达式的限制仍然很严格(如第二行继续错误所示),第 9 段的措辞似乎与 C11 中的相同,特别是继续说“对象的值不得通过使用这些运算符访问”(wrt[]和朋友)。

通过阅读标准,第一个上下文是否是有效的初始化常量,不包括第 10 段?是否有任何地方我可能会找到 GCC/Clang 更改的理由?

4

1 回答 1

2

6.6 常量表达式,¶8:

算术常量表达式应具有算术类型,并且只能具有整数常量浮点常量枚举常量字符常量、结果为整数常量的sizeof 表达式和_Alignof 表达式的操作数。算术常量表达式中的强制转换运算符只能将算术类型转换为算术类型,但作为 sizeof 或 _Alignof 运算符的操作数的一部分除外。

字符串文字不是上述 6 种允许的操作数类型中的任何一种,因此该表达式不是算术常量表达式,除非它被接受为扩展。

于 2019-06-15T16:36:28.007 回答