【问题标题】:How does gcc allocate statically run time known length of arraygcc如何分配静态运行时已知长度的数组
【发布时间】:2014-04-18 16:28:46
【问题描述】:

我写了以下代码:

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

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

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

【问题讨论】:

  • 您是在问这是如何实现的,或者考虑到它不是合法的 C++,为什么要编译?
  • @juanchopanza 这是如何实现的?

标签: c++ gcc static-allocation


【解决方案1】:

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

实现并不难;在典型的调用堆栈实现中,该函数只需要保存堆栈帧的基址,然后将堆栈指针前进动态指定的数量。 VLA 总是带有一个警告,如果数字太大,你会得到未定义的行为(在 Stack Overflow 中表现出来),这使得它们比std::vector 更难使用。

曾经有人努力在 C++ 中添加一个类似的特性,但是这在类型系统方面却出人意料地困难(例如,arr 的类型是什么?它是如何在函数模板中推导出来的? ?)。这些问题在 C 中不太明显,它具有更简单的类型系统和对象模型(但话虽如此,您仍然可以争辩说,C 因拥有 VLA 而变得更糟,相当一部分标准都花在了它们身上,而且语言会没有它们会简单得多,而且不一定会更差)。

【讨论】:

  • 它确实被添加到 C++ 并且问题得到了解决(参见 N3639),但被拉出并移动到一个覆盖数组扩展的 TS
  • @JonathanWakely 据我了解,该提案被拆分为一个单独的 TS,因为在获得批准后,不断进行足够多的更新以表明它还没有真正完成或不够稳定,无法确信一切都真的以正确的方式解决了。
  • 如果数组一开始表现良好(例如,没有指针衰减),那么 C++ 中的动态数组可能会容易得多,因为类型系统实际上会有所帮助,而不是主动阻碍。
  • @bames53:您仍然需要引入“仅动态定义的类型”的概念。是的,array-new 也有同样的问题,但是使用 array-new 你永远不会看到实际的对象,只会看到它的第一个元素。在 C 语言中,您可以看到 sizeof 由于 VLA 突然变得更加复杂......
  • @bames53,运行时绑定 (ARB) 提案数组没有问题。 std::dynarray 有更新,而不是 ARB,但有些人强烈认为这两个功能是耦合的,如果 dynarray 被移动到 TS,那么 ARB 也必须是。所以现在我们有一个关于数组扩展的 TS。
【解决方案2】:

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)的内部实现。

【讨论】:

  • alloca 不是 C 标准库的一部分。
  • @KerrekSB,正确 - 已修复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-02
  • 2010-11-27
  • 2012-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-30
相关资源
最近更新 更多