发件人:Gordon Burditt
新闻组:comp.lang.c
主题:Realloca()
日期:1999 年 1 月 25 日 09:34:09 GMT
Message-ID:<16167775DFB6601E.39220BF5766349A7.B20FE25E4B4173B2@library-proxy.airnews.net>

>我对一个叫做 alloca() 的函数有点好奇。alloca().
>我这里的 (Solaris) man 手册告诉我,它在栈上分配内存,
>这些内存会在函数返回时自动释放。现在,我很清楚
>alloca() 不是标准的,并且是依赖于系统的,超出本组的范围,alloca()alloca() 不是标准并且
>因此是系统相关的,并且超出了本组的范围,
>所以请不要为了告诉我这一点而回复。另一方面,我想知道
>它在*实践*中的可移植性如何,以及它相对于 malloc()
>等函数的优缺点。我见过它被大量使用,据推测,代码
>malloc()>等函数的优缺点。我见过它被大量使用,据推测,代码
>的作者一定有*某种*理由使用它。

这个函数是我尝试实现过的最糟糕的不兼容的怪物之一。有一些方法可以尝试用 alloca() 来实现它,malloc()alloca()

但如果内存实际上是在栈上分配的,它会引起很多问题。你几乎只能在编译器中将其作为内置函数来实现。alloca()你可以写一个了解链接约定的函数来调整栈,但在一个架构上(它不使用栈帧指针),我最终不得不每次调用都额外分配大约 128 字节,因为可能需要保存寄存器。这 128 字节的数字是*猜测*最坏情况是多少,而且我认为它包含了一些(不合理的)关于调用 alloca() 的函数的最大参数数量的假设。当函数退出时,你会拿回这些字节。如果能够实际修改编译器生成的函数退出序列,生活会简单得多。

问题是什么?嗯,如果你开始在栈上分配东西,而栈上已经有东西了,你就会alloca()在中间分配东西,这会严重破坏参数传递,因为压入栈的东西应该是连续的。一个糟糕的例子 alloca()。

    printf("%p %p %p %p %p\n", alloca(1), alloca(2), alloca(10), 
	alloca(8), alloca(20));

现在,你可以在哪里使用 alloca()?alloca()我认为这相当安全

你可以在函数最外层块的表达式语句中使用 alloca() 的形式:

	pointer_variable = alloca(expression);
作为函数最外层块的表达式语句。

如果你在不符合此描述的任何地方使用它,你就会惹上麻烦。你很可能会在以下任何地方遇到麻烦,因为在调用 alloca() 的时候,栈上可能已经有一些东西了:alloca()在循环内部。

  1. 在以局部变量开始的任何块内部,除了函数的最外层块,尤其是在退出此块后仍使用分配的内存时。
  2. 在赋值的左侧使用比指针变量更复杂的表达式,包括指针数组的一个元素。
  3. 在 alloca() 的返回值用作函数参数的上下文。
  4. 在 = 运算符的值被使用的任何上下文中,例如 alloca()。
  5. 并且我预计有人会就即使那个高度限制性的限制提出质疑,认为它对于某些编译器生成的代码来说不够保守。现在,如果它被作为编译器内置函数来完成,你可能会设法解决这些问题。
    	if ((pointer_variable = 
    		alloca(sizeof(struct something))) == NULL) { .... }
    

一旦我最终弄清楚了那个 alloca()

alloca()alloca()函数,它效果相当不错——据我回忆,它的主要用途是在一个 Bison 解析器中。每次调用浪费 128 字节,再加上固定的栈大小,可能会令人烦恼。我为什么不直接使用 GCC?因为这是试图*移植* GCC,最初使用交叉编译器,到一个内存刚好够本地编译 GCC(约 1.35 版本)的机器上。当 GCC 2 发布时,它变成了一个如此耗内存的程序,以至于本地编译自己是不可能的。

Gordon L. Burditt