【问题标题】:Why can't I initialize a variable-sized array?为什么我不能初始化可变大小的数组?
【发布时间】:2011-07-09 13:02:21
【问题描述】:

当你初始化一个可变大小的数组时,只要变量是 const,GCC 就不会出错,但如果不是,它就不会编译。

这背后的原因是什么?这样做有什么问题:

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

这根本不会编译,但如果我不初始化 test[] 那么它会编译!这对我来说没有任何意义,因为据我所知,无论如何都需要根据它的大小(7 个整数)制作一个堆栈帧来适应这个数组(这意味着我使用的整数文字并不真正有任何意义,如果我没记错的话),那么如果我初始化它有什么区别呢?

我的另一个疯狂的 C++ 设计问题...

谢谢!

【问题讨论】:

    标签: c++ arrays initialization


    【解决方案1】:
    • 数组的大小必须是常量整数表达式。
    • 整数文字是常量整数表达式。 (int arr[5];)
    • 用常量表达式初始化的常量整数变量是常量表达式。 (const int j = 4; const int i = j; int a[i];)

    • 用非常量表达式初始化的常量变量不是常量表达式

       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};我会得到一个错误。不同之处?不知道。
    • @MisterSir:您忘记指定-pedantic。没有它,gcc 不会也不会尝试成为符合标准的 C++ 实现。你不能仅仅因为 gcc 接受某些东西就得出结论,它一定是语法正确的 C++。
    • 我现在明白了.. 所以你说即使没有初始化它也不正确,但 GCC 还是允许它?此外,使用 -Wall 和 -pedantic 编译仍然只会给出警告,而不是错误。如果你说的是真的而且这只是 GCC 的设计选择,我想知道他们当时写它时的高度是什么。
    • @MisterSir:标准只要求实现诊断不正确的程序,而不是编译失败。警告是一种诊断。如果您希望不正确的程序无法编译,请使用-pedantic-errors。这不仅仅是 GCC 的设计选择,它取自 C99。
    • 您也可以使用 -std=c++98 选项。见gcc.gnu.org/onlinedocs/gcc/…
    【解决方案2】:

    这实际上更像是一个疯狂的 C99 设计问题,因为可变长度数组是 C99 的一项功能,gcc 允许在 C++ 中作为扩展。

    在 C99 中,6.7.8/3 说“要初始化的实体的类型......不是可变长度数组类型”,因此 gcc 刚刚使用了与 C99 要求的相同的扩展规则。

    C99 基本原理文档没有说明 VLA 无法初始化的原因。我可以推测这可能是因为初始化程序中存在过多元素的风险,如果为 size 提供的值结果小于初始化程序。但我不知道。

    【讨论】:

    • 可能是这样,但这只是程序员的问题,而不是语言本身的问题(因为我假设大多数程序员都知道如果他们写 int size = 27,那么数组的大小将为 27元素...)。
    • @MisterSir:当然,但是 VLA 并不是为您设计的,让您毫无意义地写 int size = 27; int arr[size]; 而不是 int arr[27];。它们专为您编写 void somefunction(int size) { int arr[size]; ... }
    【解决方案3】:

    如果您使用const int size = 7;,某些编译器允许这样做。从理论上讲,编译器可以确定它的大小是恒定的,但它没有这样做。

    【讨论】:

    • 一些编译器?!我认为任何半体面的 C++ 编译器都必须允许这样做,因为它是标准的!
    【解决方案4】:

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

    您的程序在 c++ 中根本无效,gcc 将其编译为“扩展”。你可能不得不问 gcc 的作者为什么他们决定以这种方式实现。

    【讨论】:

    • +1 那,可能的原因是它不明确。具有初始化列表的常量大小的数组初始化列表中的元素,并将其余元素初始化为零。根本没有显式大小的数组隐式使用初始化器列表的长度。具有非常量长度的数组应该做什么?除非非常量长度与初始化列表长度相同,否则两者都可以。
    • 这条评论一锤定音。
    【解决方案5】:

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

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

    C++ 中不允许使用可变长度数组,因为 C++ 为此提供了 std::vector。

    可变长度数组是C++从基于c98的C标准分支出来后在C99中引入的一个特性。 C++ 已经有 std::vector 提供可变长度数组的功能,因此 C++ 标准从不允许可变长度数组作为标准的一部分。

    如果您的编译器支持它,它是通过编译器扩展来实现的。使用 -pedantic 选项编译,它会通知你相同的警告,说它被 ISO C++ 禁止

    【讨论】:

    • @MisterSir:同意 - STL(std::vector 是其中的一部分)甚至不是原始 C++ 标准的一部分。
    • @MisterSir:希望能澄清一下。 C 标准允许 VLA(可变长度数组)C++ 不允许!
    • 我仍然不明白为什么拥有一个功能会迫使您禁止另一个功能。我的意思是,看看 malloc 和 new。
    • @MisterSir:很简单,因为 C++ 的向量比数组好得多。
    • @MisterSir:我看不出答案的哪一部分是不正确的?
    【解决方案6】:

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

    int is1[2] = {1}
    

    在没有警告的情况下编译,合理地假设用户想要 {1,0}

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

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

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

    啊哈,警告还是不警告?

    【讨论】:

      猜你喜欢
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 2020-03-20
      • 2011-09-26
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      • 2013-10-21
      相关资源
      最近更新 更多