为什么在 gcc 上接受 const 限定变量作为初始值设定项?

Lun*_*din 6 c gcc initializer static-initialization

在最新版本的 gcc(或 clang)中编译此代码时 -std=c17 -pedantic-errors -Wall -Wextra

static const int y = 1;
static int x = y;
Run Code Online (Sandbox Code Playgroud)

然后我没有收到编译器诊断消息,即使我相当确定这不是有效的 C 而是约束违规。我们可以通过查看C17 6.7.9/4来证明它是不符合的:

约束
...
具有静态或线程存储持续时间的对象的初始值设定项中的所有表达式都应为常量表达式或字符串文字。

然后是关于常量表达式的定义,在这种情况下是整数常量表达式(6.6):

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

最后是关于整数常量的定义(6.4.4.1/2):

整数常量以数字开头,但没有句点或指数部分。它可能有一个指定其基础的前缀和一个指定其类型的后缀。

因此,const int变量不是整数常量,也不是整数常量表达式。因此不是有效的初始化程序。这之前已经讨论过(例如这里),我认为已经确定这是不合格的。但是,我的问题是:

为什么 gcc 即使在严格模式下也选择不合规?

clang 显然一直不合规,但 gcc 从 7.3 版的合规变为 8.0 及更高版本的不合规。即使在没有-pedantic-errors.

似乎已经对这条消息做出了某种积极的、有意识的决定。为什么在 gcc 中完全删除它,为什么在严格模式下编译时不保留它-std=c17 -pedantic-errors

Joh*_*ger 6

为什么 gcc 即使在严格模式下也选择不合规?

由于所提出的问题是针对开发人员的动机,因此作为第三方,我们必须继续提供的唯一信息来自公共开发工件,例如 GCC bugzilla、存储库提交消息和实际代码。正如评论中指出的那样,该问题在与更改相关的 Bugzilla 评论线程中进行了讨论。

Bugzilla 的讨论似乎表明,开发人员考虑了该领域的标准要求,尽管有些敷衍。特别参见评论910。他们提出了语言规范的第 6.6/10 段:

一个实现可以接受其他形式的常量表达式。

他们没有对此进行任何特别的审查,我阅读这些评论更多的是为了寻求改变的理由,而不是对 GCC 一致性考虑的深思熟虑。

因此,他们做出更改是因为他们想要实现功能请求,并且他们在标准语言中找到了足够的(对他们来说)理由来考虑改变的行为与语言约束一致,因此不需要诊断。


还有一个隐含的问题,即最近 GCC 对提交的声明表的沉默接受是否实际上违反了符合规范的处理器诊断约束违规的义务。

尽管可以将 6.6/10 解释为允许实现接受他们选择的任何表达式,以符合任何类型的常量表达式的要求,但这似乎令人担忧。一段给定的代码是否满足语言的约束不应该依赖于实现。如果接受这些解释点中的任何一个,都可以解决该问题:

  • 6.6/10 应该被解释为表达了一个通用规则的特定情况,即一个符合的实现可以接受不符合的代码,而不意味着这样做使处理器有权将代码视为符合的。

  • 6.6/10 应该被解释为允许处理器将更多的表达式解释为“常量表达式”而不是前面段落中描述的那些,但这与这些段落中定义的特定类型的常量表达式的定义无关(“整数常量表达式”和“算术常数表达式”)。

这些并不相互排斥。我赞成后者,正如我之前所写的,我也倾向于支持前者。