如何实现可变长度参数列表?

时间:2011-12-26 20:22:55

标签: c implementation variadic-functions

调用使用varargs的函数时,内部会发生什么?参数本身是否像任何其他参数一样存储在堆上或堆栈中。如果在堆栈中,它是如何工作的?

3 个答案:

答案 0 :(得分:8)

它依赖于实现。但最有可能的是,args被一个接一个地放在堆栈上(在执行默认参数提升之后)。

va_startva_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是不可能的。