C99型VLA有哪些技术缺点?

qdi*_*dii 11 c c++ c99 variable-length-array c++11

我从许多人那里听说,在C99中引入的可变长度阵列非常糟糕.IRC的一些人在一分钟之前说过"我不认为C++会得到VLA,而strousoup对他们做了一些非常负面的评论".

这些人讨厌VLA的原因是什么?

Lun*_*din 7

VLA在运行时在堆栈上分配数组,这使得在编译时使用堆栈大小变得更加困难甚至无法确定.由于堆栈具有相当少的可用内存(与堆相比),许多人担心VLA具有很大的堆栈溢出潜力.

即将推出的MISRA-C编码标准很可能也会禁用VLA.


Chr*_*oph 6

虽然变长数组有自己的问题,我们应该记住他们是如何走过来的:作为一个替代alloca(),这可以说是甚至成问题.

虽然在PDP-11上实现起来微不足道,但在其他架构上并非如此,Ritchie和Thompson 将其从实施中删除.

然而,可变大小的自动分配显然是有用的,alloca()尽管它存在问题但仍然可以复活(特别是,它不能用于任何可能进行任意函数调用的地方,并且在许多架构上它必须是内置的编译器).C工作组同意提供这样的功能,但认为可变长度阵列是优秀的解决方案.

如果你看一下C99中添加的功能(复数,类型通用数学,restrict......),你应该注意到它们中的很多都是为了让C成为更好的数值计算语言.可变长度数组在那里也很有用,我相信Fortran当时已经拥有它们.此外,它们的引入还导致可变修改的派生类型(例如指向可变大小的数组的指针),这在处理矩阵时特别有用.


Joh*_*ode 5

正如其他人指出的那样,VLA 使堆栈帧溢出变得非常容易。我不是编译器编写者,但我的理解是 VLA 也可以成为支持的错误(它们现在在 C2011 中是可选的)。并且它们的使用仅限于块或函数范围;您不能在文件范围内使用 VLA,并且它们不能具有外部链接。

不过,我不希望看到 VLA 语法消失;当动态分配内部维度直到运行时才知道的多维数组时,它真的很方便,例如:

size_t r, c;
// get values for r and c
int (*arr)[c] = malloc(r * sizeof *arr);
if (arr)
{
   ...
   arr[i][j] = ...;
   ...
   free(arr);
}
Run Code Online (Sandbox Code Playgroud)

一个连续的分配(和一个相应free),并且我可以下标它作为一个2D阵列。替代方案通常意味着零碎分配:

size_t r, c;
...
int **arr = malloc(sizeof *arr * r);
if (arr)
{
  for (i = 0; i < c; i++)
    arr[i] = malloc(sizeof *arr[i] * c);
  ...
  arr[i][j] = ...;
  ...
  for (i = 0; i < c; i++)
    free(arr[i]);
  free(arr);
}
Run Code Online (Sandbox Code Playgroud)

或使用一维偏移:

int *arr = malloc(sizeof *arr * r * c);
if (arr)
{
  ...
  arr[i * r + j] = ...;
  ...
  free(arr);
}
Run Code Online (Sandbox Code Playgroud)