求总和函数(可变参数形式)
int average(int n,...)
{
int sum;
va_list args;
va_start(args,n);
for(int i = 0;i<n;++i)
{
sum += va_arg(args,int);
}
va_end(args);
return sum;
}
typedef char * va_list //为char* 别名为va_list
函数栈调用 对于C语言,其调用遵循_cdecl规则: 1.所有参数从右到左依次入栈。 2.这些参数由调用者清除,称为手动清除。 3.被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。(简化的将就是调用参数的类型和数量不会产生编译阶段的错误)
以求和函数举例
int sum = sum(3,4,5,6);
三个宏宏定义
(1)va_start
#define va_start _crt_va_start
#define _crt_va_start va_start(ap,v)
#define va_start(ap,v) (ap = (va_list)&v + _INTSIZEOF(v))
#define _INTSIZEOF(v) ((sizeof(v) + sizeof(int) - 1) & ~(sizeof(int)-1))
va_start宏的作用:
#define va_start(ap,v) (ap = (va_list)&v + _INTSIZEOF(v))
ap = (char*)&v + (sizeof(v) + sizeof(int) - 1) & ~(sizeof(int)-1);
参数类型: ap为va_list类型指针,即为char *,v是最后一个确定的参数。其含义是它之后的参数均为可变参数。
功能:获取可变参数中的第一个参数,并将其地址保存在ap中。
#define _INTSIZEOF(v) ((sizeof(v) + sizeof(int) - 1) & ~(sizeof(int)-1))
_INTSIZEOF(v)宏函数是为了对齐内存。
(2)va_arg
#define va_arg(ap,t) (*(t*))(ap += _INTSIZEOF(t) - _INTSIZEOF(t))
va_arg宏的作用:
参数类型: ap为va_list类型的指针,即char,它指向当前需要获取的参数。t为当前参数的类型。
功能: 获取ap当前所指向参数的指针,并将其强制转化为 *t,并进行解引用 ,然后将ap指向可变参数表的下一个参数。
(3)va_end
#define va_end(ap) (ap = (va_list)0)
ap = (char*)0 = NULL;
va_end宏的作用:
参数类型: ap为va_list类型的指针 。
功能: 使指针指向空,不在使用该指针。防止ap成为野指针,进行错误引用。实际上通常va_start与va_end是配对使用。
了解并掌握以上三个宏的使用方法以及函数栈调用的规则后。
下面开始分析求和可变参数函数的实现过程:
int average(int n,...) //...表示参数的类型和数量不确定 n表示传入参数的个数
{
int sum;
va_list args; //相当于定义 char *p;
va_start(args,n); //获取可变参数列表中的第一个参数的地址并保存在p内 va_start(p,n)
for(int i = 0;i<n;++i)
{
sum += va_arg(args,int);
}
va_end(args); // 等价于*p = NULL;
return sum;
}