Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。
尽管有上述特性,为什么不鼓励使用alloca() ?
Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。
尽管有上述特性,为什么不鼓励使用alloca() ?
当前回答
这里的大多数回答都忽略了一点:使用_alloca()可能比仅仅在堆栈中存储大对象更糟糕,这是有原因的。
自动存储和_alloca()之间的主要区别是,后者有一个额外的(严重的)问题:分配的块不受编译器控制,因此编译器无法优化或回收它。
比较:
while (condition) {
char buffer[0x100]; // Chill.
/* ... */
}
:
while (condition) {
char* buffer = _alloca(0x100); // Bad!
/* ... */
}
后者的问题应该是显而易见的。
其他回答
答案就在手册页中(至少在Linux上):
返回值 函数的作用是:返回一个指向对象开头的指针 分配空间。如果 分配的原因 堆栈溢出,程序行为未定义。
这并不是说它永远不应该被使用。我工作的一个OSS项目广泛使用它,只要你不滥用它(分配巨大的值),它是好的。一旦超过了“几百字节”的标记,就应该转而使用malloc和friends。您可能仍然会遇到分配失败,但至少您会得到一些失败的指示,而不是仅仅耗尽堆栈。
进程只有有限的堆栈空间可用——远远小于malloc()可用的内存量。
通过使用alloca(),您将极大地增加获得Stack Overflow错误的机会(如果幸运的话,或者如果运气不好,则会出现莫名其妙的崩溃)。
在我看来,alloca()在可用的情况下,应该仅以受约束的方式使用。就像“goto”的使用一样,相当多理智的人不仅对alloca()的使用非常反感,而且对它的存在也非常反感。
对于嵌入式使用,其中堆栈大小是已知的,并且可以通过对分配大小的约定和分析施加限制,并且编译器不能升级到支持C99+,使用alloca()是很好的,而且我已经知道使用它。
When available, VLAs may have some advantages over alloca(): The compiler can generate stack limit checks that will catch out-of-bounds access when array style access is used (I don't know if any compilers do this, but it can be done), and analysis of the code can determine whether the array access expressions are properly bounded. Note that, in some programming environments, such as automotive, medical equipment, and avionics, this analysis has to be done even for fixed size arrays, both automatic (on the stack) and static allocation (global or local).
在堆栈上存储数据和返回地址/帧指针的架构上(据我所知,这就是它们的全部),任何堆栈分配变量都可能是危险的,因为变量的地址可以被取走,未检查的输入值可能会允许各种各样的恶作剧。
在嵌入式领域,可移植性不是一个太大的问题,但是它是反对在严格控制的环境之外使用alloca()的一个很好的理由。
在嵌入式空间之外,我主要在日志记录和格式化函数中使用alloca()以提高效率,并在非递归词法扫描器中使用,其中临时结构(使用alloca()在标记化和分类期间创建,然后在函数返回之前填充持久对象(通过malloc()分配)。对较小的临时结构使用alloca()可以在分配持久对象时极大地减少碎片。
这里的大多数回答都忽略了一点:使用_alloca()可能比仅仅在堆栈中存储大对象更糟糕,这是有原因的。
自动存储和_alloca()之间的主要区别是,后者有一个额外的(严重的)问题:分配的块不受编译器控制,因此编译器无法优化或回收它。
比较:
while (condition) {
char buffer[0x100]; // Chill.
/* ... */
}
:
while (condition) {
char* buffer = _alloca(0x100); // Bad!
/* ... */
}
后者的问题应该是显而易见的。
可悲的是,真正强大的alloca()在几乎强大的tcc中缺失了。Gcc确实有alloca()。
它播下了毁灭自己的种子。用return作为析构函数。 像malloc()一样,它在失败时返回一个无效的指针,这将在有MMU的现代系统上分段故障(希望重新启动那些没有MMU的系统)。 与自动变量不同,您可以在运行时指定大小。
它可以很好地用于递归。您可以使用静态变量来实现与尾递归类似的功能,并使用其他几个变量向每次迭代传递信息。
如果你推得太深,你肯定会出现段错误(如果你有一个MMU)。
注意,malloc()没有提供更多,因为当系统内存不足时,它会返回NULL(如果分配了NULL,也会出现段错误)。也就是说,你所能做的就是保释或试图以任何方式转让它。
要使用malloc(),我使用全局变量并将其赋值为NULL。如果指针不是NULL,我在使用malloc()之前释放它。
如果想复制任何现有数据,也可以使用realloc()作为一般情况。在使用realloc()之前,您需要检查指针,以确定是否要在realloc()之后复制或连接。
3.2.5.2 alloca的优点