C标准库中<stdarg.h>头文件中包含可变参数列表的实现,完成遍历未知数目和类型的函数参数列表的功能。提供以下3个宏以及va_list变量:
va_start(va_list ap, lastarg):在提取可变参数前必须调用这个宏实现初始化。
va_arg(va_list ap, type_of_var):用于提取变量,type_of_var是提取的变量的类型。返回对应类型的参数。
va_end(va_list ap):在参数处理完毕之后,必须调用va_end做一些清理。
通过这3个宏就可以实现可变参数的遍历,下面看一下多字符的复制和链接的实现,这两个函数都是通过NULL作为可变参数列表的终结。
|--------------|
| 23 | 最后一个可变参数
|--------------| 0x10000008
| 12 | 第一个可变参数
|--------------| 0x10000004
| 1 | 最后一个固定参数
%ebp--> |--------------| 0x10000000
| |
|--------------|
............
|--------------|
| |
%esp--> |---------------|
CPU的%ebp是帧指针,%esp是栈指针,在%ebp和%esp之间的内存就是当前函数的栈帧,传给当前函数的实参是在调用函数的栈帧中,顺序放置在%ebp后面。比如上图就是调用avg(1, 12, 23)的栈对应的状态。根据栈的状态,a对应的是1,a的起始地址是0x10000000,va_list变量实际就是char *,当调用va_list(ap, a)后,ap对应的就是0x10000004。当调用int n = va_arg(ap, int),相当于执行(*(int *)ap)也就是12,然后将ap += sizeof(int),这时ap指向0x10000008,也就是根据传入va_arg的类型type,跳过sizeof(type)个字节,这样去遍历可变参数。这是我对于可变参数的实现的理解和猜测,不一定对啊。。。