为啥 alloca 与创建局部变量不同?
Posted
技术标签:
【中文标题】为啥 alloca 与创建局部变量不同?【英文标题】:Why is alloca different from just creating a local variable?为什么 alloca 与创建局部变量不同? 【发布时间】:2011-11-07 16:47:51 【问题描述】:我读到有一个名为 alloca 的函数,它从当前函数的堆栈帧而不是堆中分配内存。函数退出时内存自动销毁。
这有什么意义,它与仅在函数中创建结构数组或局部变量有何不同?它们会进入堆栈,也会在函数结束时被销毁。
PS:我看到了另一个 alloca 问题,它没有回答这两个问题有何不同:)
【问题讨论】:
【参考方案1】:在 gcc 和 C99 采用可变长度数组之前,alloca
提供的功能比简单的局部变量要强大得多,因为您可以分配直到运行时才知道长度的数组。
在两个数据表示之间的边界可能会出现这种需求。在我的 postscript 解释器中,我在内部使用计数字符串;但如果我想使用库函数,我必须转换为以 nul 结尾的表示来进行调用。
OPFN_ void SSsearch(state *st, object str, object seek)
//char *s, *sk;
char s[str.u.c.n+1], sk[seek.u.c.n+1]; /* VLA */
//// could also be written:
//char *s,*sk;
//s = alloca(str.u.c.n+1);
//sk = alloca(seek.u.c.n+1);
char *r;
//if (seek.u.c.n > str.u.c.n) error(st,rangecheck);
//s = strndup(STR(str), str.u.c.n);
//sk = strndup(STR(seek), seek.u.c.n);
memcpy(s, STR(str), str.u.c.n); s[str.u.c.n] = '\0';
memcpy(sk, STR(seek), seek.u.c.n); sk[seek.u.c.n] = '\0';
r = strstr(s, sk);
if (r != NULL) int off = r-s;
push(substring(str, off + seek.u.c.n, str.u.c.n - seek.u.c.n - off)); /* post */
push(substring(str, off, seek.u.c.n)); /* match */
push(substring(str, 0, off)); /* pre */
push(consbool(true));
else
push(str);
push(consbool(false));
//free(sk);
//free(s);
alloca
也有一个危险的用法,使用 VLA 很容易避免这种用法。您不能在函数调用的参数列表中安全地使用alloca
。所以永远不要这样做:
char *s = strcpy(alloca(strlen(t)+1, t);
这就是 VLA 的用途:
char s[strlen(t)+1];
strcpy(s,t);
【讨论】:
【参考方案2】:我认为以下是不同的:
void f()
int x;
int * p = &x;
// no more x
void g()
int * p = alloca(sizeof(int));
// memory still allocated
【讨论】:
我会试一试,这将是一个有趣的区别 :) 你可能是对的,因为我认为 alloca 提到了函数范围。 很可能在这两种情况下仍然分配了内存。x
name 不再可用,但它所代表的内存仍分配给堆栈——编译器通常不会在每次进入或离开新范围时调整堆栈指针。
@Rob:好的,增加示例以在块之后添加更多声明。在第一种情况下,您会为x
重用内存,而在第二种情况下,您不会...【参考方案3】:
当您使用alloca
时,您可以指定在运行时需要多少字节。使用局部变量,数量在编译时是固定的。请注意,alloca
早于 C 的可变长度数组。
【讨论】:
【参考方案4】:使用alloca
,您可以创建一个动态数组(通常需要malloc
),而且速度非常快。这里有GCCalloca
的优缺点:
http://www.gnu.org/s/hello/manual/libc/Variable-Size-Automatic.html#Variable-Size-Automatic
【讨论】:
“GCC alloca”是什么意思?alloca
通常定义为编译器内在函数。通常它不是“标准”功能。我认为在 GCC 中也是如此。例如看到这个:linux.die.net/man/3/alloca以上是关于为啥 alloca 与创建局部变量不同?的主要内容,如果未能解决你的问题,请参考以下文章