调用使用varargs的函数时,内部会发生什么?参数本身是否像任何其他参数一样存储在堆上或堆栈中。如果在堆栈中,它是如何工作的?
答案 0 :(得分:8)
它依赖于实现。但最有可能的是,args被一个接一个地放在堆栈上(在执行默认参数提升之后)。
va_start
,va_arg
等只需将指针移到堆栈中,然后将这些位重新解释为您要求的任何类型。
答案 1 :(得分:5)
之前已经注意到,它依赖于实现。
在C调用约定(称为cdecl
)中,参数以相反的顺序被推入堆栈中,因此:
void myfunc(int one, int two, int three)
调用后,在堆栈中看起来像这样(堆栈向上增长,朝向0):
. . 0x00000000
. .
. .
| current frame |
|----------------|
| return address |
|----------------| ^
| one | | stack
|----------------| | growth
| two | | direction
|----------------| |
| three |
|----------------|
| previous frame |
...
... 0xFFFFFFFF
因此,可以首先获取第一个参数(因为我们知道它的位置,它就在返回地址之前),并且希望它包含有关存在多少其他参数的足够信息。例如,在printf(3)
和相关函数中,有关其他参数的所有信息都存在于格式字符串中,这是第一个参数。
答案 2 :(得分:1)
在C中,函数参数被调用函数推入和拉出堆栈。调用者函数知道有多少项被推送,因此它也可以在通话后将它们拉回来。被调用者只能从其他参数中推断出参数的数量,例如格式字符串printf()
。
例如,在Pascal中,堆栈上的参数由被调用者提取。由于被调用者不知道推送的项目数,因此无法将堆栈恢复到先前的状态。这就是为什么在Pascal中实现varargs是不可能的。