【问题标题】:When are variable-length arrays legal?什么时候变长数组是合法的?
【发布时间】:2011-08-09 11:05:23
【问题描述】:

我不是 C++ 专家,但据我所知,由于 size 不是常量,这段代码应该会失败:

#include<iostream>

using namespace std;

int main(int argc, char** argv)
{
  int size = *argv[1] - 48;
  char array [size];
  cout<<sizeof(array)<<endl;

  return 0;
}

为什么当我用 gcc(最好是 g++)编译它时它会起作用?

./test 7
7
/test 2 
2

【问题讨论】:

    标签: c++ gcc


    【解决方案1】:

    要从堆栈或堆中为变量分配内存,需要知道变量的大小。 C++ 编译器可以自行决定如何分配内存,但 c++ 已经公开了他们期望 c++ 编译器如何处理这种情况,因此 c++ std 要求编译器供应商发布他们的内存处理。这通过 sizeof 运算符发生。该运算符完全在编译时计算。数组大小的编译时限制来自此要求。

    int arr[10];
    std::cout << sizeof(arr) << std::endl
    

    由于每个变量和类型都支持 sizeof,因此它们的大小需要在 c++ 的编译时计算。因此可变长度数组在 C++ 中是不可能的。

    此要求还有另一个非常重要的限制。原则上 c++ 编译器供应商可以计算 c++ 程序堆栈所需的最大内存量,只要没有一个问题:对于递归函数,您无法计算程序使用的堆栈大小,但对于其他一切,堆栈的大小可以计算方法如下:

    1. 对堆栈帧中的每个变量使用 sizeof(a)
    2. 对变量的大小求和以获得该堆栈帧所需的内存量
    3. 列出所有可能的堆栈帧并计算它们的大小
    4. 选择最大的调用栈
    5. 选择该大小作为程序堆栈的大小。

    不幸的是,递归函数破坏了整个方案。并且它需要全局程序的流分析来重新识别哪些函数可能具有无限的调用堆栈。但是编译时 sizeof 运算符的限制很重要,否则我们的 c++ 程序会随机耗尽堆栈空间,从而导致崩溃和不稳定。这是不可接受的。因此每个变量和类型都支持编译时 sizeof 运算符。

    VLA 支持要求编译器可以生成代码,其中通常生成的偏移量作为生成的机器代码的常量实际上可以在运行时修改。符合标准的 c++ 编译器通常无法做到这一点。 C 决定添加这种支持,因此 C 编译器可以做到这一点。但在这个过程中,他们需要打破 sizeof 运算符。不再可以在编译时计算大小。 C 标准中规定的 VLA 支持存在很大问题:

    1. 您不能将 VLA 放入结构或类中
    2. VLA 基本上仅限于本地函数范围

    这些问题已经在 c++ 中通过 std::vector 解决了,没有任何这些问题。

    【讨论】:

      【解决方案2】:

      这是一个list of new features in C99,它添加了variable length arrays

      另请参阅N1548ISO/IEC 9899:201x 委员会草案 - 2010 年 12 月 2 日 N1548)的 $6.7.6.2/4 数组声明符,其中详细说明了它。

      【讨论】:

      • 但是:没有 C++ 标准接受来自 C99 的 VLA,因此从技术上讲,在 C++ 中接受 VLA 的事实是 g++ 扩展。
      【解决方案3】:

      这是一个非标准的 GCC 扩展 - Visual C++ 等其他编译器不支持。

      【讨论】:

        【解决方案4】:

        这是一个 C99 功能,允许您在堆栈上声明类似的数组。

        【讨论】:

          【解决方案5】:

          c99 支持可变长度数组(VLA),但 c90 和 C++ 都不支持可变长度数组,但 gcc 支持这一点,因为 an extension in both C and C++ 如果使用这些参数进行编译,您可以更清楚地看到这一点:

          gcc -std=c89 -pedantic
          

          这会给你以下警告:

          warning: ISO C90 forbids variable length array ‘array’ [-Wvla]
          

          g++:

          g++ -pedantic
          

          会给你这个警告:

          warning: ISO C++ forbids variable length array ‘array’ [-Wvla]
          

          gcc 手册中的 standards 部分详细介绍了此内容。需要注意的是,从 2011 年开始,C 标准可变长度数组 (VLA) 现在是可选的。

          【讨论】:

            【解决方案6】:

            即使没有 VLA 扩展,当编译器无法推断出维度表达式在编译时未知时,代码也可以编译。还是 UB。

            【讨论】:

              【解决方案7】:

              因为您不调用 g++ 作为 C++ 编译器。如果我尝试它,我会收到一条警告,明确指出“ISO C++ 禁止可变长度数组”。但我的 makefile 包含选项 -std=c++98,至少在我想编译可移植 C++ 时是这样。

              【讨论】:

                猜你喜欢
                • 2012-08-19
                • 1970-01-01
                • 2012-07-16
                • 1970-01-01
                • 1970-01-01
                • 2023-03-05
                • 1970-01-01
                • 2012-02-28
                • 1970-01-01
                相关资源
                最近更新 更多