为啥 const 限定变量被接受为 gcc 上的初始化程序?
Posted
技术标签:
【中文标题】为啥 const 限定变量被接受为 gcc 上的初始化程序?【英文标题】:Why are const qualified variables accepted as initializers on gcc?为什么 const 限定变量被接受为 gcc 上的初始化程序? 【发布时间】:2021-09-16 00:35:15 【问题描述】:在最新版本的 gcc(或 clang)中使用 -std=c17 -pedantic-errors -Wall -Wextra
编译此代码时
static const int y = 1;
static int x = y;
然后我没有收到编译器诊断消息,即使我相当确定这不是有效的 C 而是违反约束。我们可以通过查看 C17 6.7.9/4 来证明它是不合格的:
约束 ... 具有静态或线程存储持续时间的对象的初始化程序中的所有表达式都应为常量表达式或字符串文字。
然后是关于常量表达式的定义,本例为整数常量表达式(6.6):
整数常量表达式应该是整数类型,并且只能有整数常量、枚举常量、字符常量、结果为整数常量的 sizeof 表达式、_Alignof 表达式和浮点常量的操作数。类型转换的直接操作数。
最后是关于整数常量的定义(6.4.4.1/2):
整数常量以数字开头,但没有句点或指数部分。它可能有一个指定其基数的前缀和一个指定其类型的后缀。
因此,const int
变量不是整数常量,也不是整数常量表达式。因此不是有效的初始化程序。这已经在之前讨论过(例如here),我认为已经确定这是不合格的。但是,我的问题是:
为什么 gcc 即使在严格模式下也选择不合规?
clang 显然一直是不合规的,但是 gcc 从 7.3 版的合规变成了 8.0 及更高版本的不合规。 gcc 7.3 及更早版本即使在没有-pedantic-errors
的默认模式下也会给出“错误:初始化元素不是常量”。
似乎已经对这条信息做出了某种积极、有意识的决定。为什么它在 gcc 中被完全删除,为什么他们没有在严格模式下编译时保持原样-std=c17 -pedantic-errors
?
【问题讨论】:
如果有人能找到 clang 选择不合规的理由,那也很有趣。不过,我将这个问题专门留给 gcc,以避免一次问两个问题。 这能回答你的问题吗? Why "initializer element is not a constant" is... not working anymore? @jdm 在 KamilCuk 提出的问题中发表了评论,该评论链接到这个 gcc 错误:gcc.gnu.org/bugzilla/show_bug.cgi?id=69960,我认为通过记录讨论来回答您的问题。 @AlexLop。不,这没有回答“为什么 gcc 即使在严格模式下也选择不合规?”的问题。如问题中所述,我们已经确定这是不合规的,这不是我要问的。 @PaulHankin 不是真的,这只是各种不那么混乱的随机 cmets。编译器不允许静默忽略约束违规。 【参考方案1】:为什么 gcc 即使在严格模式下也选择不合规?
由于所提出的问题是针对开发人员的动机,我们作为第三方必须继续提供的唯一信息来自公共开发工件,例如 GCC bugzilla、存储库提交消息和实际代码。正如 cmets 所指出的,这件事在the Bugzilla comment thread associated with the change 中讨论。
Bugzilla 的讨论似乎表明开发人员考虑了该标准在这方面的要求,尽管以一种有些敷衍的方式。具体参见 cmets 9 和 10。他们提出了语言规范的第 6.6/10 段:
一个实现可以接受其他形式的常量表达式。
他们不会对此进行任何特别的审查,我认为 cmets 更多地是为了寻求改变的理由,而不是对 GCC 一致性考虑的深思熟虑的调查。
因此,他们做出更改是因为他们想要实现功能请求,并且他们发现(对他们而言)标准语言中有足够的理由认为更改后的行为与语言限制一致,因此不需要诊断.
还有一个隐含的问题,即最近 GCC 对所提出的声明表格的默许接受是否实际上违反了合规处理器诊断违反约束的义务。
虽然可以将 6.6/10 解释为允许实现接受他们选择的任何表达式,以符合任何类型的常量表达式的要求,但这似乎令人担忧。一段给定的代码是否满足语言的约束不应该依赖于实现。如果接受这些解释点中的任何一个,都可以解决该问题:
6.6/10 应被解释为表达了一般规则的特定情况,即符合标准的实现可以接受不符合标准的代码,而不是暗示这样做使处理器有权将代码视为符合标准。
6.6/10 应该被解释为允许处理器将比前面段落中描述的更多的表达式解释为“常量表达式”,但这与那些段落中定义的特定类型的常量表达式的定义无关(“整数常量表达式”和“算术常量表达式”)。
这些不是相互排斥的。我订阅后者as I have written previously,我也倾向于前者。
【讨论】:
所以我们对这个短语有几个相互竞争的解释,在某种程度上都是合理的。无论该标准的实际意图是什么,措辞都是草率的,应该加以修正。 “给定的一段代码是否满足语言的约束不应该依赖于实现”。我不敢苟同。int main(void) int x[sizeof(long)-5];
无法以独立于实现的方式进行一致性分析。
假设标准允许实现接受“改进的常量表达式”(不是整数或算术常量表达式)。如果不列举允许这些表达而其他表达不被允许的上下文,这种许可意味着什么?如果一个实现也被允许为它们定义允许的上下文,这实际上与允许较少约束的整数/算术常量表达式相同,除了新的应该以不同的方式命名。
@n.1.8e9-where's-my-sharem., 接受假设的“改进的常量表达式”是有意义的,因为有多种上下文需要常量表达式而不指定整数常量表达式或算术常量表达式。没有必要指定仅可以使用改进的常量表达式的特定上下文。以上是关于为啥 const 限定变量被接受为 gcc 上的初始化程序?的主要内容,如果未能解决你的问题,请参考以下文章