5

根据这个答案,其中指出:

编译器知道 int 类型的大小,因此可以生成正确的汇编指令,该指令将在堆栈上保留足够的空间,以便让 foo 存在。

编译器需要知道函数在堆栈上占用的大小才能实现它。

那么,为什么这段代码会编译呢?

int f(int n)
{
    int x[n];
}

int main()
{
    f(3);
    f(5);
    //etc
}

x是一个整数数组,但它的大小不是恒定的,它可以在函数被调用的任何时候改变。

我在这里想念什么?

4

3 回答 3

8

这不是标准 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;
}
于 2013-04-08T19:38:18.027 回答
4

它编译是因为您使用的是非标准扩展。从严格意义上讲,它不是有效的 C++,但一些编译器确实支持这一点。

在您的情况下(已知 3 和 5),您可以改用模板,这将是有效的,或者直接使用std::vector.

template<int n>
int f()
{
    int x[n];
}

//...
f<3>();
于 2013-04-08T19:38:12.260 回答
0

在这种情况下,编译器的工作确实更难。它现在需要发出代码,这些代码将在运行时确定需要多少内存(n*sizeof(int))以及从哪里获取内存。该内存仍然在与释放位置相同的位置int y[5];释放,因此在这方面没有任何变化。

编译器的一种简单解决方案是将幕后代码更改为int * __x = malloc(n*sizeof(int)... free(__x)。它可能还需要为 重写一些代码sizeof(x),但编译器也可以将 VLA 代码重写为“普通”代码。不需要魔法;VLA 可以仅作为语法糖来实现。

于 2013-04-08T20:21:29.577 回答