是否需要从堆栈中分配 C 可变长度数组?

Posted

技术标签:

【中文标题】是否需要从堆栈中分配 C 可变长度数组?【英文标题】:Is it required that a C Variable Length Array is allocated from the stack? 【发布时间】:2016-01-06 08:16:12 【问题描述】:

从我们的嵌入式系统代码中删除所有对 malloc 和 calloc 的调用后,我惊讶地发现 malloc 仍在链接中。调用图将我指向一个没有显式 *alloc 调用的函数,并且不调用任何可能分配的库函数,例如strdup。 我必须查看生成的程序集才能意识到这是由于包含 VLA 的内联函数造成的。

我认为 VLA 必须是堆栈分配的。这个编译器坏了吗?

【问题讨论】:

与程序的堆栈大小相比,分配的 VLA 有多大? 在这种情况下,大小参数是uint8_t,所以最坏的情况是 256 字节,大约是堆栈的 1/5。 如果没有堆栈溢出的机会(我的意思是真正的 :-),为什么不使用最坏的情况,即一些 char arr[256] 而不是 VLA? 我确实把它改成了固定的。问题的重点是揭穿commonassumptionthat VLAs arealways stack。 【参考方案1】:

没有要求从堆栈中分配 VLA(语言标准甚至没有提到堆栈或堆)。唯一的要求如下:

6.2.4 对象的存储时长 ... 7 对于这种具有可变长度数组类型的对象,它的生命周期从 对象的声明直到程序执行离开了范围 声明。35) 如果递归输入范围,则创建对象的新实例 每一次。对象的初始值是不确定的。
35) 离开包含声明的最里面的块,或跳转到该块中的某个点或 声明之前的嵌入块,离开声明的范围。

鉴于此,从堆栈分配是有意义的,但是对于 非常大 的对象,这可能是不可能的,并且可以从堆或其他一些内存段中分配这样的对象。簿记取决于实施。

【讨论】:

如果您通过制作一个太大的 VLA 或一系列函数调用中的一系列 VLA 超出了它们的堆栈大小限制,大多数实际实现只会出错。仅当您知道大小会受到限制时才使用 VLA,即使在非叶函数中也要小心。 允许通过单独分配 VLA 将您从自己手中拯救出来,但不是必须的。【参考方案2】:

不,它们不必进行堆栈分配。如果您希望它在堆栈上,我会使用 alloca

来源1:https://***.com/a/2035292/283342

其次,VLA 通常分配在堆栈上,但由于它的可变大小,通常情况下它在内存中的确切位置在编译时是未知的。出于这个原因,底层实现通常必须将其实现为指向内存块的指针。这引入了一些额外的内存开销(对于指针),由于上述原因,这又是完全无关紧要的。这也带来了轻微的性能开销,因为我们必须读取指针值才能找到实际的数组。这与访问 malloc-ed 数组时的开销相同(而不是使用命名的 compile-time-sized 数组)。

来源 2:https://en.wikipedia.org/wiki/Variable-length_array

一种语言对 VLA 的支持可能隐藏的一个问题是底层内存分配问题:在堆和堆栈之间有明显区别的环境中,可能不清楚其中哪一个(如果有的话)将存储 VLA。

【讨论】:

以上是关于是否需要从堆栈中分配 C 可变长度数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何查找变量是在堆栈还是堆中分配?

C 可变长度数组存储持续时间

如何在C中的堆栈中分配超过所需的内存?

如何在 C++ 中分配一个二维指针数组

在 Fortran 中分配字符数组

在 Fortran 中分配字符数组