根据这份答复,其中指出:
编译器知道int类型的大小,因此可以生成正确的汇编器指令,该指令将在堆栈上保留足够的空间,以便让foo驻留在那里。
编译器需要知道函数将在堆栈上占用的大小才能实现它。
那么,为什么这段代码会编译?
int f(int n)
{
int x[n];
}
int main()
{
f(3);
f(5);
//etc
}
x
是一个整数数组,但它的大小不是恒定的,它可以在调用函数时随时更改。
我错过了什么?
这不是标准C中的合法代码。它的编译要归功于您的编译器特有的扩展,该扩展支持可变长度数组,这是C99特性。
但同样,这不是可移植的C。如果您需要动态调整大小,您可以这样重写您的函数:
#include <vector>
int f(int n)
{
std::vector<int> v(n);
}
否则,将其设为模板并这样写:
#include <array>
template<std::size_t N>
int f()
{
std::array<int, N> a;
}
它编译是因为您使用的是非标准扩展。从严格意义上说,它不是有效的C,但有些编译器确实支持这一点。
在您的情况下(3和5是已知的),您可以使用模板来代替,这将是有效的,或者直接使用std::向量
。
template<int n>
int f()
{
int x[n];
}
//...
f<3>();
在这种情况下,编译器的工作确实更难。它现在需要发出代码,这些代码将在运行时计算出需要多少内存(n*sizeof(int)
),以及从哪里获取内存。该内存仍然在释放int y[5];
的同一位置释放,因此在这方面没有任何变化。
编译器的一个简单解决方案是将幕后代码更改为int*__x=malloc(n*sizeof(int)
…free(__x)
。它可能还需要为sizeof(x)
重写一些代码,但编译器也可以将VLA代码重写为“普通”代码。不需要魔法;VLA可以仅仅作为语法糖来实现。