可变数量的参数

时间:2013-11-25 22:27:36

标签: c++ c variadic-functions

关于可变数量的论点,我有几个问题:

  1. 为什么将va_startva_argva_end定义为宏而不是函数?

  2. va_start如何运作?它是否可以访问函数调用堆栈并遍历堆栈,直到找到最后指定的参数?

3 个答案:

答案 0 :(得分:2)

7.15 变量参数部分Rationale for International Standard—Programming Languages—C中介绍了它们为什么是宏的基本原理:

  

va_start和va_arg必须以宏的形式存在,因为va_start使用的参数是   通过名称传递,va_arg使用一个参数,该参数是数据类型的名称。

本文How Variable Argument Lists Work in C详细介绍了原因并提供了可能的 x86 实现:

typedef char *va_list;
#define va_start( list, param ) (list = (va_list)(&param + sizeof( param )))
#define va_arg( list, type )    (*(type *)((list += sizeof( type )) - sizeof( type ))

C ++ 中,您有很多其他选择,Variable number of arguments in C++?可能涵盖所有其他选择。

答案 1 :(得分:1)

va_end不需要实现为宏,我认为也不会实现va_start(您只需要将&添加到参数中以传递指针对于他们而言。实际上va_endva_start必须被视为宏,因为在所有情况下都不能使用&,正如评论中所指出的那样。 / p>

va_arg必须作为宏实现,因为您需要提供一个类型作为参数,如果没有宏,就不能这样做。

va_start按照你的假设工作:你给它第一个参数,它可以根据参数的大小计算其他参数的位置,因为它们在堆栈上都是连续的。

它只是启动va_list指向第一个参数的末尾(您传递给va_start)并在每次使用va_arg时添加下一个参数的大小。< / p>

答案 2 :(得分:0)

va_startva_argva_end通常必须在可变参数函数的上下文中执行才能完成工作,因此将它们设置为函数会使它们复杂得多,或者(在某些情况下)完全无法实施。

其工作原理的细节留待实施。在典型情况下,可变参数函数的参数将从左向右推,因此第一个参数将最接近堆栈的顶部。为了实现它,va_arg只需要知道堆栈帧的基本结构,例如返回地址的大小(顶部参数通常就在它旁边)。