【问题标题】:Is indexing a string literal an initializer constant expression?索引字符串文字是初始化常量表达式吗?
【发布时间】:2019-10-29 21:30:34
【问题描述】:

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

static char x = "abcx"[3];

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

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

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

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

    李>
  • 对于这两个编译器,行为最近发生了变化 - Clang 过去在 3.8 之前会引发错误,而 GCC 过去会在 8.0 之前引发错误。这些版本分别于 2016 年和 2018 年推出。这表明更改是有意的,但我还没有找到任何一个编译器的发行说明,涉及到这种详细程度。

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

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

【问题讨论】:

  • 我碰巧认为这应该被允许作为一个真正的 ICE,但这只是个人意见。
  • 如果不计算 6.10(实现可能接受其他形式的常量表达式。),很明显,仅 6.6 就不是整数常量表达式。因此,未能在-pedantic 下报告它应该被视为一个错误,IMO。 (就 -pedantic 而言,我认为编译器不应该考虑 6.10。)
  • 来自the answer to my question,看起来很相似,我前段时间问过:“GCC 的-pedantic 选项确保仅在标准要求的情况下进行诊断,不包括这些情况。”该标准在接受常量表达式的实现形式时不需要诊断,因此-pedantic 不会发出任何问题。像-Wimplementation-constant-expression 这样的标志会很酷。 (这是重复的吗?)
  • 是什么让您认为更改是故意的?对我来说似乎是一个 gcc 错误。虽然显然 clang 和 icc 总是允许这个代码。

标签: c language-lawyer c11 constant-expression c17


【解决方案1】:

6.6 常量表达式,¶8:

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

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

【讨论】:

  • 第 10 段说“一个实现可以接受其他形式的常量表达式。”由于实现不需要标准的特殊许可即可接受其他形式的常量表达式作为扩展,我认为可以合理地将第 10 段解释为接受其他形式的常量表达式不需要被视为扩展。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
  • 2011-05-28
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多