【问题标题】:How are Variable Length Array instructions generated?可变长度数组指令是如何生成的?
【发布时间】:2020-08-04 13:18:53
【问题描述】:

C 支持可变长度数组:

int main(){
   int num = 5;
    int arr[num];
    return 0;
}

我了解arr 是在运行时分配的。这是如何实现的? 它是否调用 C 运行时函数来分配再见?由于在编译期间分配量是未知的,因此不应该存在用于堆栈分配的指令。

作为一个附带问题,将它们用于malloc 和堆分配是否是一种好习惯,因为 VLA 在 C++ 中不受官方支持?

编辑:

似乎可以使用在堆栈帧上分配的alloca 来实现。

【问题讨论】:

  • VLA 在 C11 中也“仅”可选地支持(这意味着并非所有符合 C11 的编译器都需要支持它)
  • 在您的示例中,分配量在编译时是已知的,当分配 arr 时,num 只能是 5。但您可以 scanf("%d", &num); 使其未知。

标签: c variable-length-array


【解决方案1】:

如何完成 VLA 分配取决于个人实现 - 我熟悉的那些从堆栈分配,但他们不必这样做。

VLA 很有用,但仅限于非常有限的情况。由于它们的大小直到运行时才知道,它们不能是 struct 类型的成员,它们不能具有 static 存储持续时间,并且它们的大小可能受到限制。如果您需要不太大的临时存储(大约几千字节左右)并且您不知道它有多大,并且不需要在当前范围之外持续存在,那么 VLA可以很方便并且比动态内存更容易处理。

不过,从 2011 年起,VLA 支持是可选,所以我不会过分依赖它们。

【讨论】:

  • 因为它首先存在,所以我倾向于使用alloca.h 等。人。因为我通常只需要一个一维数组,并且如果我必须稍后切换,它与malloc 更兼容,因为该大小将不再适合堆栈。但是,只是好奇,将 VLA 支持更改为可选的理由是什么?
  • @CraigEstey:我认为它们会在堆栈空间有限的嵌入式环境中引起问题。
【解决方案2】:

不只是,正如你所说的那样

VLA 在 C++ 中不受官方支持。

但自 C11 以来它们也被归为 “可选功能”(尽管它们仅在 C99 中添加!)。这实际上是不使用它们的原因,目的是拥有可移植的代码。


不幸的是,它的内存分配细节依赖于实现。大多数编译器通常将它们作为自动存储变量分配在堆栈中(根据我的研究和个人经验),但也可以在堆中分配。

在堆栈中分配数组可能会导致堆栈溢出问题,尤其是在嵌入式环境中。我建议访问this question(关于 C++ 标准不支持 VLA);特别是 @Quuxplusone 的 this answer 真的很有趣(重点是我的):

C99 中的可变长度数组基本上是一个失误。为了支持 VLA,C99 不得不 [...] 对常识做出让步。

在 C++ 世界中不那么重要,但对于 C 的嵌入式系统程序员的目标受众来说非常重要,声明 VLA 意味着在你的堆栈中任意大块地咀嚼。这是有保证的堆栈溢出和崩溃。(无论何时声明 int A[n],您都在暗示您有 2GB 的堆栈可用。毕竟,如果您知道“n 肯定小于 1000这里”,那么你只需声明 int A[1000]


据我所知,它们的主要优点是具有局部范围的可变长度数组,这是其他替代方案无法实现的:

/* Fixed length array, either global or local */
int arr[100];

/* Dynamic allocation */
int * arr = malloc (100 * sizeof (int));

在大多数情况下,无论如何,开发人员要么

  • 知道 VLA 可以拥有的最大大小。那么为什么不以固定长度静态分配它呢?
  • 无法控制最大大小,因此他们必须执行完整性检查以避免堆栈溢出。那么为什么不用固定长度分配来限制它的大小呢?

【讨论】:

    【解决方案3】:

    作为一个附带问题,将它们用于 malloc 和堆分配是否是一种好习惯,

    不,请考虑使用flexible array members 作为可变大小struct-s 的last 成员。检查malloc 在运行时没有失败。

    在嵌入式编程中,当您可以保证 VLA-s 足够小,因为您不想炸毁您的 call stack 时,它们非常有用。 int arr[num]; 前面有一个最小值,前面有 assert(num>0 && num<100); 或更好的东西,在运行时添加这样的检查。您可以使用像 Frama-C 这样的工具来静态地证明这一点。

    【讨论】:

      猜你喜欢
      • 2012-01-02
      • 1970-01-01
      • 2022-11-17
      • 2012-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 2019-03-14
      相关资源
      最近更新 更多