构造指向 alloca 的函数指针会导致链接器错误?
Constructing a function pointer to alloca causes linker errors?
我正在尝试编写一个函数,该函数传递一个函数以用于分配作为其参数;它应该接受 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);
}
标准版的行为方式不同是否有原因?
引用来自 here 的手册页:
The fact that the code is inlined means that it is impossible to take
the address of this function, or to change its behavior by linking
with a different library.
该页面还提到:
messy consequences if one has a private version of this function
谁说你的功能
static inline void *alloca(size_t n) {
return __builtin_alloca(n);
}
有效吗?由 __builtin_alloca
分配的对象在函数结束时满足其生命周期,所以一旦你 return 它,你就已经有了一个悬空指针!
你不能按照你的建议去做。 alloca
是一个非常特殊的野兽,它只能在函数体内显式调用,而不能在函数调用的参数表达式中调用。
请注意 alloca
没有 标准版本。 C 标准和 POSIX 都没有描述这个函数。
您公开的替代方案,将 alloca
重新定义为调用 __builtin_alloca
的内联函数不起作用:除其他问题外,__builtin_alloca()
返回的指针仅在调用方之前有效returns,是否内联
linux man page 非常明确:
[...]
DESCRIPTION
The alloca()
function allocates size bytes of space in the stack
frame of the caller. This temporary space is automatically freed
when the function that called alloca()
returns to its caller.
RETURN VALUE
The alloca()
function returns a pointer to the beginning of the
allocated space. If the allocation causes stack overflow, program
behavior is undefined.
[...]
CONFORMING TO
This function is not in POSIX.1.
There is evidence that the alloca()
function appeared in 32V, PWB,
PWB.2, 3BSD, and 4BSD. There is a man page for it in 4.3BSD. Linux
uses the GNU version.
NOTES
The alloca()
function is machine- and compiler-dependent. For
certain applications, its use can improve efficiency compared to the
use of malloc(3)
plus free(3)
. In certain cases, it can also
simplify memory deallocation in applications that use longjmp(3)
or
siglongjmp(3)
. Otherwise, its use is discouraged.
Because the space allocated by alloca()
is allocated within the stack
frame, that space is automatically freed if the function return is
jumped over by a call to longjmp(3)
or siglongjmp(3)
.
The space allocated by alloca()
is not automatically deallocated if
the pointer that refers to it simply goes out of scope.
Do not attempt to free(3)
space allocated by alloca()
!
Notes on the GNU version
Normally, gcc(1) translates calls to alloca()
with inlined code.
This is not done when either the -ansi
, -std=c89
, -std=c99
, or the
-std=c11
option is given and the header <alloca.h>
is not included.
Otherwise, (without an -ansi
or -std=c*
option) the glibc version of
<stdlib.h>
includes <alloca.h>
and that contains the lines:
#ifdef __GNUC__
#define alloca(size) __builtin_alloca (size)
#endif
with messy consequences if one has a private version of this function.
The fact that the code is inlined means that it is impossible to take
the address of this function, or to change its behavior by linking
with a different library.
The inlined code often consists of a single instruction adjusting the
stack pointer, and does not check for stack overflow. Thus, there is
no NULL
error return.
BUGS
There is no error indication if the stack frame cannot be extended.
(However, after a failed allocation, the program is likely to receive
a SIGSEGV
signal if it attempts to access the unallocated space.)
On many systems alloca()
cannot be used inside the list of arguments
of a function call, because the stack space reserved by alloca()
would appear on the stack in the middle of the space for the function
arguments.
我正在尝试编写一个函数,该函数传递一个函数以用于分配作为其参数;它应该接受 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);
}
标准版的行为方式不同是否有原因?
引用来自 here 的手册页:
The fact that the code is inlined means that it is impossible to take the address of this function, or to change its behavior by linking with a different library.
该页面还提到:
messy consequences if one has a private version of this function
谁说你的功能
static inline void *alloca(size_t n) {
return __builtin_alloca(n);
}
有效吗?由 __builtin_alloca
分配的对象在函数结束时满足其生命周期,所以一旦你 return 它,你就已经有了一个悬空指针!
你不能按照你的建议去做。 alloca
是一个非常特殊的野兽,它只能在函数体内显式调用,而不能在函数调用的参数表达式中调用。
请注意 alloca
没有 标准版本。 C 标准和 POSIX 都没有描述这个函数。
您公开的替代方案,将 alloca
重新定义为调用 __builtin_alloca
的内联函数不起作用:除其他问题外,__builtin_alloca()
返回的指针仅在调用方之前有效returns,是否内联
linux man page 非常明确:
[...]
DESCRIPTION
The
alloca()
function allocates size bytes of space in the stack frame of the caller. This temporary space is automatically freed when the function that calledalloca()
returns to its caller.RETURN VALUE
The
alloca()
function returns a pointer to the beginning of the allocated space. If the allocation causes stack overflow, program behavior is undefined.[...]
CONFORMING TO
This function is not in POSIX.1.
There is evidence that the
alloca()
function appeared in 32V, PWB, PWB.2, 3BSD, and 4BSD. There is a man page for it in 4.3BSD. Linux uses the GNU version.NOTES
The
alloca()
function is machine- and compiler-dependent. For certain applications, its use can improve efficiency compared to the use ofmalloc(3)
plusfree(3)
. In certain cases, it can also simplify memory deallocation in applications that uselongjmp(3)
orsiglongjmp(3)
. Otherwise, its use is discouraged.Because the space allocated by
alloca()
is allocated within the stack frame, that space is automatically freed if the function return is jumped over by a call tolongjmp(3)
orsiglongjmp(3)
.The space allocated by
alloca()
is not automatically deallocated if the pointer that refers to it simply goes out of scope.Do not attempt to
free(3)
space allocated byalloca()
!Notes on the GNU version
Normally, gcc(1) translates calls to
alloca()
with inlined code. This is not done when either the-ansi
,-std=c89
,-std=c99
, or the-std=c11
option is given and the header<alloca.h>
is not included. Otherwise, (without an-ansi
or-std=c*
option) the glibc version of<stdlib.h>
includes<alloca.h>
and that contains the lines:#ifdef __GNUC__ #define alloca(size) __builtin_alloca (size) #endif
with messy consequences if one has a private version of this function.
The fact that the code is inlined means that it is impossible to take the address of this function, or to change its behavior by linking with a different library.
The inlined code often consists of a single instruction adjusting the stack pointer, and does not check for stack overflow. Thus, there is no
NULL
error return.BUGS
There is no error indication if the stack frame cannot be extended. (However, after a failed allocation, the program is likely to receive a
SIGSEGV
signal if it attempts to access the unallocated space.)On many systems
alloca()
cannot be used inside the list of arguments of a function call, because the stack space reserved byalloca()
would appear on the stack in the middle of the space for the function arguments.