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

8
在我们为嵌入式系统的代码中删除了所有对malloc和calloc的调用后,我惊讶地发现仍然链接了malloc。调用图将我指向一个没有显式*alloc调用的函数,并且没有调用任何可能分配内存的库函数,比如 strdup
我不得不查看生成的汇编代码才意识到,这是由一个包含VLA的内联函数引起的。

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


可变长数组(VLA)在分配时与程序的堆栈大小相比有多大? - Matt
在这种情况下,size参数是uint8_t,所以最坏情况下需要256字节,大约是堆栈的五分之一。 - AShelly
如果没有堆栈溢出的可能(我的意思是真正的),为什么不使用最坏情况,即一些char arr [256]而不是VLA? - Matt
1
我已将其更改为固定大小。问题的主要目的是揭示常见的假设,即可变长度数组(VLAs)始终位于堆栈上。这一点可以从以下链接中得到证实:common assumption that VLAs are always stack - AShelly
2个回答

9
没有要求VLAs必须从栈中分配(语言标准甚至没有提到堆栈或堆)。唯一的要求如下:
6.2.4 对象的存储期限…对于这样一个具有可变长度数组类型的对象,它的生命周期从声明该对象开始,直到程序执行离开该声明作用域为止。如果递归进入该作用域,则每次都会创建一个新实例。该对象的初始值是不确定的。
鉴于此,从栈中分配是有意义的,但对于非常大的对象可能无法做到,这样的对象可能会从堆或其他内存段中分配。其管理由实现决定。

大多数真实的实现只会在您创建一个过大的VLA或一系列VLA时超出其堆栈大小限制而导致故障。仅在您知道大小将受到限制的情况下使用VLAs,即使在非叶函数中也要小心。实现可以通过单独分配VLAs来防止您自己的错误,但不是必需的。 - Peter Cordes

5
不,它们不必是堆栈分配的。如果您希望它在堆栈上,则可以使用alloca。 来源1:https://dev59.com/bHI-5IYBdhLWcg3wCz7y#2035292 其次,VLA通常在堆栈上分配,但由于其大小可变,在一般情况下,其在内存中的确切位置在编译时是未知的。因此,底层实现通常必须将其实现为指向内存块的指针。这会引入一些额外的内存开销(用于指针),但出于上述原因,这完全是微不足道的。这也会引入轻微的性能开销,因为我们必须读取指针值才能找到实际的数组。这与访问malloc的数组时获得的开销相同(并且不使用命名的编译时大小的数组时不会获得)。 来源2:https://en.wikipedia.org/wiki/Variable-length_array 在语言支持可变长度数组的情况下,可能隐藏着底层内存分配的问题:在堆和栈有明确区别的环境中,可能不清楚哪一个(如果有)将存储VLA。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接