GCC如何分配静态运行的数组长度

How does gcc allocate statically run time known length of array

本文关键字:运行 数组 静态 何分配 分配 GCC      更新时间:2023-10-16

我写了以下代码:

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

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

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

这是GCC为C 提供的扩展名,尽管C99自C99以来,C均适当地支持了可变长度数组(" VLAS")。

实施并不难;在典型的呼叫堆栈实现中,该功能只需要保存堆栈框架的底座,然后通过动态指定的金额推进堆栈指针。VLA总是提出警告:如果数字太大,您会得到不确定的行为(在堆栈溢出中表现出来),这使它们比std::vector

在某个时候努力为C 添加类似的功能,但是事实证明,对于类型系统而言,这非常困难(例如,arr的类型是什么?如何在功能模板中推导它?)。这些问题在C中的可见程度较低,C具有更简单的类型系统和对象模型(但是,您仍然可以说,C的情况更糟,因为拥有VLA,标准的很大一部分都花在它们上,并且语言将会没有它们,它变得更简单,不一定要差)。

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)