我正在尝试编写一个传递给函数以用作分配参数的函数;它应该接受类型为void *(*)(size_t)
的任何有效分配器。但是,当尝试使用alloca
作为分配器时,我遇到奇怪的行为-构造指向alloca
函数的函数指针可以正常编译,但会导致链接器错误:
#include <stdlib.h>
#include <alloca.h>
int main() {
void *(*foo)(size_t) = alloca;
}
产生
/tmp/cc8F67yC.o: In function `main':
test15.c:(.text+0x8): undefined reference to `alloca'
collect2: error: ld returned 1 exit status
这与被内联的alloca有关系吗?但是当函数不需要地址时,不会仅作为优化来进行内联。实际上,使用GCC,我什至可以编写自己的版本,该版本可以按上述代码的预期运行:
static inline void *alloca(size_t n) {
return __builtin_alloca(n);
}
是否有标准版本的行为方式不相同的原因?
答案 0 :(得分:6)
谁说你的功能
static inline void *alloca(size_t n) {
return __builtin_alloca(n);
}
有效吗?由__builtin_alloca
分配的对象在函数结束时达到其生存期,因此,一旦返回它,就已经有一个悬空指针了!
答案 1 :(得分:5)
答案 2 :(得分:2)
您不能做您建议的事情。 alloca
是一种非常特殊的野兽,只能在函数体内显式调用,而不能在函数调用的参数表达式内显式调用。
请注意,没有alloca
的标准版本。 C标准和POSIX均未描述此功能。
使用alloca
重新定义为调用__builtin_alloca
的内联函数时公开的替代方法不起作用:除其他问题外,__builtin_alloca()
返回的指针仅在调用者返回之前有效,是否内联。
linux man page非常明确:
[...]
描述
alloca()
函数在堆栈中分配大小字节的空间 呼叫者的框架。此临时空间会自动释放 当调用alloca()
的函数返回到其调用者时。返回值
alloca()
函数返回一个指针,该指针指向 分配的空间。如果分配导致堆栈溢出,请编程 行为是不确定的。[...]
符合
此功能不在POSIX.1中。
有证据表明
alloca()
功能出现在32V,PWB, PWB.2、3BSD和4BSD。在4.3BSD中有一个手册页。的Linux 使用GNU版本。注释
alloca()
函数与机器和编译器有关。对于 在某些应用中,与 使用malloc(3)
加free(3)
。在某些情况下,它也可以 在使用longjmp(3)
的应用程序中简化内存的重新分配siglongjmp(3)
。否则,不建议使用。因为
alloca()
分配的空间是在堆栈内分配的 框架,如果函数返回为,则该空间会自动释放 通过调用longjmp(3)
或siglongjmp(3)
跳过了。如果发生以下情况,则
alloca()
分配的空间不会自动释放: 指向它的指针完全超出范围。请勿尝试
free(3)
分配的空间alloca()
!有关GNU版本的说明
通常,gcc(1)使用内联代码将调用转换为
alloca()
。-ansi
,-std=c89
,-std=c99
或 提供了-std=c11
选项,但不包含标头<alloca.h>
。 否则,(没有-ansi
或-std=c*
选项)的glibc版本<stdlib.h>
包括<alloca.h>
,其中包含以下行:#ifdef __GNUC__ #define alloca(size) __builtin_alloca (size) #endif
如果拥有此功能的私有版本,将带来混乱的后果。
内联代码这一事实意味着无法接受 该函数的地址,或通过链接更改其行为 使用其他库。
内联代码通常由一条指令调整 堆栈指针,并且不检查堆栈溢出。因此,有 没有
NULL
错误返回。BUGS
如果不能扩展堆栈帧,则没有错误指示。 (但是,分配失败后,该程序很可能会收到
SIGSEGV
信号,如果它试图访问未分配的空间。)在许多系统上,
alloca()
不能在参数列表中使用 函数调用的时间,因为alloca()
保留的堆栈空间 将出现在函数中间的堆栈中 争论。