变长数组何时合法?

nae*_*aeg 4 c++ gcc

我不是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;
}
Run Code Online (Sandbox Code Playgroud)

当我使用gcc编译它时,为什么这可行(更好的说是g ++)?

./test 7
7
/test 2 
2
Run Code Online (Sandbox Code Playgroud)

小智 5

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

int arr[10];
std::cout << sizeof(arr) << std::endl
Run Code Online (Sandbox Code Playgroud)

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

此要求还有另一个非常重要的限制.原则上,c ++编译器供应商可以计算c ++程序堆栈所需的最大内存量,如果只有一个问题:对于递归函数,你不能计算程序使用的堆栈大小,但对于其他一切,堆栈的大小可以通过执行以下操作来计算:

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

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

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

  1. 你不能把VLA放在结构或类中
  2. VLA基本上局限于本地功能范围

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


cni*_*tar 1

这是 C99 的一项功能,允许您像在堆栈上那样声明数组。