C99型VLA有哪些技术缺点?

时间:2012-09-13 13:46:42

标签: c++ c c++11 c99 variable-length-array

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

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

4 个答案:

答案 0 :(得分:7)

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

即将推出的MISRA-C编码标准很可能也禁止使用VLA。

答案 1 :(得分:6)

尽管可变长度数组存在问题,但应该记住它们是如何形成的:作为alloca()的替代,可以说是even more problematic

虽然在PDP-11上实施起来微不足道,但其他架构和Ritchie和Thompson removed it from their implementation并非如此。

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

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

答案 2 :(得分:4)

正如其他人所指出的,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);
}

一个连续的分配(和一个对应的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);
}

或使用1-d偏移:

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

答案 3 :(得分:2)

VLA使堆栈溢出更容易。在大多数使用VLA的地方,您可以根据其中一个函数参数来确定长度。如果参数是您不期望的,则最终可能会在堆栈上分配一个非常大的数组。除非您可以确定没有参数组合可以导致您溢出堆栈,否则您应该使用动态分配。

使用它们可能有意义的一个地方是在嵌入式平台上,因为在进行嵌入式编程时,少数情况是您可能会密切跟踪内存使用情况,以确保您不会堆栈溢出。