可变参数列表是通过stdarg.h内的宏来实现的:
类型 va_list
三个宏:
va_start
va_arg
va_end
我们可以声明一个va_list变量,与这三个宏配合使用。
可变参数必须要有一个命名参数,因为可变参数是通过栈来实现的,函数中的最右边的参数最先入栈。
void function(int a, int b, int c) { int d; ... }
其栈结构为
0x1ffc-->d
0x2000-->a
0x2004-->b
0x2008-->c
栈的空间是连续的,所以函数第一个必须是命名参数,这样就可以通过第一个参数来寻址,根据类型所占字节偏移,获取后续的所有可变参数值。
下面是利用可变参数计算平均值函数:
#include <stdarg.h> float average(int n_num, ...) { int count; float sum = 0; //var_arg是一个指针,通过va_start指向第一个命名参数位置 va_list var_arg; va_start(var_arg, n_num); for (count = 0; count < n_num; count++) { //va_arg第二个参数是类型,根据类型来偏移获取参数值 sum += va_arg(var_arg, int); } //让指针指向NULL,不在指向堆栈 va_end(var_arg); return sum / n_num; }
所以这些宏存在两个问题,一来无法确定参数数量,因为不同类型所占空间不同,二来无法确定类型,printf函数的类型是通过字符串中的格式字符串来提取类型实现的。