为什么我不能初始化一个变长数组?

10

如果变量是const,那么使用变量大小的数组进行初始化时,GCC不会报错,但如果变量不是const,则无法编译。这是什么原因?这样做有何问题呢?

int size = 7;
int test[size] = {3, 4, 5};

完全无法编译,但如果我不初始化test[],那么它就可以编译!对我来说这毫无意义,因为据我所知,栈帧需要根据其大小(7个整数)适应此数组,无论如何(这意味着我使用的整数字面值实际上没有任何意义,如果我没有弄错的话),因此,初始化与否有什么区别呢?

又是我疯狂的C++设计问题之一...

谢谢!

6个回答

9
  • The size of the array must be a constant integral expression.
  • An integral literal is a constant integral expression. (int arr[5];)
  • A constant integral variable initialized with a constant expression is a constant expression. (const int j = 4; const int i = j; int a[i];)

  • A constant variable initialized with a non-constant expression is not a constant expression

     int x = 4;  // x isn't constant expression because it is not const
     const int y = x; //therefore y is not either
     int arr[y]; //error)
    

你发布的代码在GCC下实际上并没有出现任何错误。编译正常,这就是我感到困惑的原因。如果我将int arr[y]更改为int arr[y] = {3, 2},那么就会出现错误。区别在哪里?我不知道。 - Lockhead
4
你忘了加上-pedantic选项。如果没有它,gcc就不是遵循C++标准的实现,也不会试图如此。你不能仅仅因为gcc接受某些东西就得出结论它一定是符合语法规范的C++代码。 - Steve Jessop
我现在明白了。所以你的意思是即使没有初始化也是不正确的,但GCC仍然允许吗?而且,使用-Wall和-pedantic编译仍然只会给出警告,而不是错误。如果你说的是真的,那么这只是GCC的设计选择,我想知道他们写这个时候喝了什么东西。 - Lockhead
@MisterSir:标准只要求实现对不正确的程序进行诊断,而不是使其无法编译。警告是一种诊断。如果您希望不正确的程序无法编译,请使用“-pedantic-errors”。这不仅是GCC的设计选择,也是从C99中引入的。 - Steve Jessop
你也可以使用 -std=c++98 选项。请参阅 http://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#C-Dialect-Options - Mankarse
VLS在C++中是GCC的扩展:即使它不在C++标准中,他们决定实现一个额外的功能。他们可能之所以这样做是因为C99也这样做了。 - Ciro Santilli OurBigBook.com

5
实际上这更像是一个疯狂的C99设计问题,因为可变长度数组是来自C99的特性,gcc允许其作为C++扩展使用。
在C99中,6.7.8/3说:“要初始化的实体的类型...不是可变长度数组类型”,所以gcc使用了与C99所需相同的规则来扩展其功能。
C99的理由文件没有说明为什么VLA不能被初始化。我可以推测可能是因为初始化程序中存在过多元素的风险,如果提供给大小的值小于初始化程序,则会出现此情况。但我不知道。

可能是这样,但那只是程序员的问题,而不是语言本身(因为我认为大多数程序员都知道如果他们写了int size = 27,那么数组的大小将是27个元素...)。 - Lockhead
@MisterSir: 当然可以,但是可变长度数组(VLAs)并不是为了让你无意义地写int size = 27; int arr[size];取代int arr[27];而设计的。它们是为了让你写void somefunction(int size) { int arr[size]; ... }这样的代码。 - Steve Jessop

4

http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html得知,“ISO C99允许使用可变长度自动数组,在C90模式和C++中,GCC作为扩展也接受它们。”

你的程序在C++中根本无效,而GCC将其编译为“扩展”。你可能需要询问GCC的作者为什么决定以这种方式实现。


+1 这很可能是因为它不明确。具有初始化列表的常量大小数组将初始化与列表中相同数量的元素并将其余部分初始化为零。根本没有显式大小的数组隐式使用初始化程序列表的长度。那么,具有非常数长度的数组应该怎么办?除非非常数长度与初始化列表长度相同,否则它可以执行任何操作。 - Damon
这个评论直接点到了问题的要害。 - user180574

4
一些编译器允许您使用const int size = 7;,如果您这样做的话。理论上,编译器可以弄清楚它是常量大小,但它实际上没有这样做。

2
一些编译器?!我认为任何半靠谱的C++编译器都必须允许这个,因为这是标准! - Armen Tsirunyan

3

这段代码在标准C++中无效。

根据C++标准(8.3.4.1)规定,数组大小必须是常量表达式

C++不允许使用可变长度数组,因为它提供了std::vector来实现此功能。

可变长度数组是在C++从基于c98的C标准分支出后,C99引入的一项功能。由于C++已经有了std::vector来提供可变长度数组的功能,所以C++标准从未允许可变长度数组成为标准的一部分。

如果您的编译器支持它,那么它是通过编译器扩展实现的。使用-pedantic选项进行编译,它会发出警告,指出ISO C++禁止使用可变长度数组。


@MisterSir:同意 - STL(其中std :: vector是一部分)甚至不是最初的C ++标准的一部分。 - DaveR
@MisterSir:简单来说,因为C++有vector,它比数组要好得多。 - Alok Save
@MisterSir:我不明白答案的哪一部分是错误的,需要被踩? - Alok Save
@Als:这基本上完全基于你自己的假设。只有在你添加了关于标准的部分之后,我才能点赞它。 - Lockhead
@MisterSir:在这里,C++中的VLA是一个如此经常被问及和讨论的话题,以至于我认为几乎每个人都知道它。顺便说一下,我从来没有假设过,我一直知道它是标准的一部分。 - Alok Save
显示剩余3条评论

0

我不确定gcc设计者在实现这个扩展时的意图,但gcc扩展工作方式的一个可能原因是:

int is1[2] = {1}

编译时没有警告,合理假设用户想要 {1,0}

int is2[1] = {1,2};

编译时出现警告,编译器应该怎么处理?

int i;
cin >> i;
int is3[i] = {1,2}

啊哈,要警告还是不要警告?


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