可变参函数

使用示例

stdargs

实现原理

va_list

va_list 是一个字符指针类型。
typedef char *va_list; 

va_start

va_start用于初始化 va_list, 取第一个参数(从左向右)的地址再向高地址偏移LASTARG大小,实际上指向了第二个参数(从左向右)

#ifndef __sparc__
#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) //AP即va_list

#else
#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif

__builtin_saveregs()是在gcc 的库程序libgcc2.c 中定义的,用于保存寄存器。
它的说明可参见gcc 手册章节“Target Description Macros”中的
“Implementing the Varargs Macros”小节。

__va_rounded_size

__va_rounded_size定义了取整后的TYPE 类型的字节长度值。是int 长度(4)的倍数。

#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

va_arg

va_arg先让AP偏移到指向下一个参数的位置,再返回要取的参数

#define va_arg(AP, TYPE) \
(AP += __va_rounded_size (TYPE), \
*((TYPE *) (AP - __va_rounded_size (TYPE))))

va_end

va_end 必须在va_arg 读完所有的参数后再被调用。
va_end 可以修改AP 使其在重新调用va_start 之前不能被使用(把va_list指向NULL)。
void va_end (va_list); // 在gnulib 中定义

#define va_end(AP)

Linux内核代码Acenv.h中也定义了一组宏

linuxstdargs