13

我从很多人那里听说 C99 中引入的可变长度数组很糟糕。IRC 上的一些人在一分钟前说“我不认为 C++ 会获得 VLA,strosoup 对它们发表了一些非常负面的评论”。

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

4

4 回答 4

10

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

即将发布的 MISRA-C 编码标准版本很可能也将禁止 VLA。

于 2012-09-13T14:03:31.560 回答
7

尽管可变长度数组有其问题,但应该记住它们是如何产生的:作为 的替代品alloca(),这可以说是更成问题

虽然在 PDP-11 上实现它是微不足道的,但在其他架构上并非如此,Ritchie 和 Thompson将它从他们的实现中删除。

然而,可变大小的自动分配显然已经足够有用,alloca()尽管它存在问题,但它还是得到了复活(特别是,它不能在任何可能调用任意函数的地方使用,而且在许多架构上它必须是内置的编译器)。C 工作组同意提供这样的功能,但认为可变长度数组是更好的解决方案。

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

于 2012-09-13T18:45:08.723 回答
6

正如其他人指出的那样,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),可以将其下标为二维数组。替代方案通常意味着零碎分配:

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);
}

或使用一维偏移:

int *arr = malloc(sizeof *arr * r * c);
if (arr)
{
  ...
  arr[i * r + j] = ...;
  ...
  free(arr);
}
于 2012-09-13T15:24:02.737 回答
2

VLA 使堆栈溢出变得更加容易。在您将使用 VLA 的大多数地方,您会将长度基于函数参数之一。如果参数不是您所期望的,您最终可能会在堆栈上分配一个非常大的数组。除非您可以确定没有任何参数组合会导致堆栈溢出,否则您应该使用动态分配。

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

于 2012-09-13T13:59:00.490 回答