为什么我的C++编译器会接受变长数组(VLAs),即使这个特性不是标准的?

23
正如我们已经知道的那样,VLA(在C99中标准化)不是C++标准的一部分,所以下面的代码在C++中是"非法"的:
void foo(int n) {
  int vla[n];
  for (int i = 0; i < n; ++i) {
    vla[i] = i;
  }
}

尽管编译器(g++和clang++)接受该代码作为有效的语法,但只有在启用-pedantic标志时才会产生警告。
ISO C++禁止变长数组'vla'[-Wvla]
我的问题是:
1. 为什么编译器接受这个声明? 编译器不能拒绝长度在编译时未知的数组吗? 是否有一种兼容性语法规则需要遵循?
2. 标准对此有何规定? 从生成的汇编代码中可以看到,编译器在循环中像普通数组一样写入堆栈,但我找不到关于标准行为的任何信息。

你提出了两个问题,而不是一个。 - Lightness Races in Orbit
4
编译器扩展只是扩展功能,不改变原有功能。 - StoryTeller - Unslander Monica
5
只是产生一个警告,以防启用了“-pedantic”标志。这就是“-pedantic”承诺的全部内容。“-pedantic-errors”则会产生这些错误。 - milleniumbug
编译器(g++和clang++)接受代码,只有在它们的默认模式下(允许扩展)。如果您启用严格的C++符合性模式(我建议这样做),则代码将不会被接受。对于C++20,请使用-std=c++20(默认为-std=gnu++20)和-pedantic - Jesper Juhl
2个回答

19
为什么编译器接受这个声明?
因为它的作者选择让它这样做。
特别是GCC,默认情况下允许很多非标准的东西,这些东西在旧的C编译器中被历史上接受过。他们在这方面喜欢"兼容性"。
关于这个问题,标准有什么说法?
C++语法中包含了对数组声明的以下规则[dcl.array]
在一个声明 T D 中,其中 D 的形式为
     D1 [ constant-expressionopt ] attribute-specifier-seqopt

[...] 在 D 中的 declarator-id 的类型是 "derived-declarator-type-list 数组,其元素类型为 T,长度为 N"

简单来说,这意味着只有常量表达式才能用于指定数组的大小。在你的例子中,n 不是一个常量表达式。 C++ 没有可变长度数组(VLA)。 当你看到一个被接受的时候,那是编译器的扩展;要了解该编译器如何实现这样的扩展,你需要询问编译器的作者(或者检查其源代码,如果适用的话)。

9
“禁止”有点过于强烈了。一般来说,标准并不禁止扩展。只要一个实现正确地处理正确形式的程序并发出所需的诊断信息,它就是符合规范的实现。如果该实现还为某些不良形式的程序提供可重复的行为,它仍然是符合规范的;标准并不关心不良形式的程序。 - rici
@rici 告诉GCC开发人员吧!“标准不关心格式错误的程序”这是错的!它确实关心,只是没有强制要求它们在编译时失败。这种“允许扩展”的做法都源于这种宽容。 - Lightness Races in Orbit
我的陈述与gcc的行为有何不同之处?我认为这种宽容完全是适当的;它允许编译器实现和测试对语言的建议添加,这是gcc和clang开发人员都在做的事情。(标准如何表达其对格式错误程序的关注?它足以将它们标记为格式错误,并明确地不定义它们的行为。) - rici
1
@rici:警告信息显示“ISO C++禁止使用可变长度数组”。你说“标准并没有禁止扩展”。如果不深入探讨基本的阅读理解,我无法进一步阐述这两个断言之间的区别,但我相信您不需要 :) - Lightness Races in Orbit
“标准如何表达对格式错误程序的关注?它只需要将其标记为格式错误并明确不定义其行为。”是的,这就是它表达关注的方式。如果它不关心,甚至不会提及它们。 - Lightness Races in Orbit
显示剩余3条评论

5
标准要求符合规范的编译器在遇到非法内容时必须“发出诊断”。完成这一步后,它可以自由地继续编译代码,并具有特定于实现的含义。(请注意,“具有特定于实现的含义”是“具有未定义行为”的委婉说法)。

3
可能不完全是"未定义行为":未定义、未指定和实现定义的行为 - Brent Bradburn
@nobar -- 标准并没有说明代码做什么,也不要求实现记录它的行为。这就是“未定义行为”。确切地说。 - Pete Becker
1
如果存在未定义行为(UB),且编译器决定在该情况下精确记录其发出的代码,那么它就会有效地变成该平台上的实现定义行为:您可以在该平台上安全使用它,但是该代码将不再可移植到其他平台。就像您依赖于 sizeof(int) == 4 一样。 - cmaster - reinstate monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接