gcc如何分配静态运行时间已知的数组长度

时间:2014-03-13 18:00:31

标签: c++ gcc static-allocation

我写了以下代码:

int tester(int n)
{
    int arr[n];
    // ...
}

使用g ++编译此代码,没有警告。

我的问题是 - 如何?参数n在运行时是已知的,在数组中是静态分配的。 gcc是如何编译的?

2 个答案:

答案 0 :(得分:7)

这是GCC为C ++提供的扩展,尽管自C99以来C可以正确支持可变长度数组(" VLA")。

实施并不是非常困难;在典型的调用堆栈实现中,该函数只需要保存堆栈帧的基础,然后按动态指定的量推进堆栈指针。如果数量太大,你会得到未定义的行为(在Stack Overflow中显示),这使得它们比使用std::vector更加苛刻。

在某种程度上,我们已经努力为C ++添加一个类似的功能,但就类型系统而言,这种结果出乎意料地难以理解(例如arr的类型是什么?它是如何推断出来的?功能模板?)。这个问题在C语言中不那么明显,它有一个更简单的类型系统和对象模型(但是说,你仍然认为C对于拥有VLA更糟糕,标准的相当一部分花费在它们上,语言会如果没有它们,它们会变得更加简单,并且不一定会更糟糕。)

答案 1 :(得分:3)

GNU C库提供了一个在堆栈上分配内存的函数 - alloca(3)。它只是递减堆栈指针,从而在其上创建一些临时空间。 GCC使用alloca(3)来实现C99可变长度数组 - 它首先递减函数序言中的堆栈指针,为所有自动变量创建空间,其大小在编译时已知,然后使用alloca(3)进一步递减它并为arr创建空间,其大小在运行时确定。优化器可能实际上融合了两个减量。

int tester(int n)
{
   int arr[n];
   return 0;
}

编译成

;; Function tester (tester)

tester (int n)
{
  int arr[0:D.1602D.1602] [value-expr: *arr.1];
  int[0:D.1602D.1602] * arr.1;
  long unsigned int D.1610D.1610;
  int n.0;
  ...

<bb 2>:
  n.0 = n;
  ...
  D.1609D.1609 = (long unsigned int) n.0;
  D.1610D.1610 = D.1609D.1609 * 4;
  D.1612D.1612 = __builtin_alloca (D.1610D.1610); <----- arr is allocated here
  arr.1 = (int[0:D.1602D.1602] *) D.1612D.1612;
  ...

这相当于以下C代码:

int tester(int n)
{
   int *arr = __builtin_alloca(n * sizeof(int));
   return 0;
}

__builtin_alloca()是GCC在alloca(3)的内部实施。