我从许多人那里听说,在C99中引入的可变长度阵列非常糟糕。 IRC的一些人在一分钟之前说过“我不认为C ++会得到VLA,而strousoup对他们做了一些非常负面的评论”。
那些人讨厌VLA的原因是什么?
答案 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的地方,您可以根据其中一个函数参数来确定长度。如果参数是您不期望的,则最终可能会在堆栈上分配一个非常大的数组。除非您可以确定没有参数组合可以导致您溢出堆栈,否则您应该使用动态分配。
使用它们可能有意义的一个地方是在嵌入式平台上,因为在进行嵌入式编程时,少数情况是您可能会密切跟踪内存使用情况,以确保您不会堆栈溢出。