可变参数的产生:首先看一段简单求平均数代码:
int average(int num,int v1,int v2,int v3,int v4)
{
return (v1+v2+v3+v4)/num;
}
#include <stdio.h>
int main()
{
int ret=average(4,1,4,5,6);
printf("%d\n",ret);
return 0;
}
此代码中求平均值函数中有5个形参,在传参过程中average(4,1,4,5,6)也传了5个实参才能得出正确结果,也只能限定5个参数,在VS2010中,若调用函数实参个数小于形参个数或者大于形参个数编译器会直接报错,如:
所以这个程序是不可移植的,所以我们需要一种机制,它能够以一种良好定义的方法访问数量未定的参数列表,所以由此产生可变参数列表来实现这一功能。
可变参数列表是通过宏来实现的,定义与stdarg.h头文件中,如下内容:
_INTSIZEOF(n)宏算出参数n类型的字节大小;
_ADDRESSOF(v)得出v的地址;
在_crt_va_arg(ap,t)中,ap先+=t类型大小,即ap值已经改变指向下一个,在减去t类型大小,并*引用最后得到上一个参数的值,最后这个宏就为上一个参数的值,ap值也已经改变;
va_list为一个typedef的char*类型,将以上程序使用可变参数列表实现:
#include <stdarg.h> #include <stdio.h> float Average(int n_values,...)//省略号代表可变参数部分 { int i=0; float sum=0; //定义一个va_list(即char*类型)变量var_arg va_list var_arg; //调用va_start宏初始化变量var_arg使它指向可变参数部分的第一个参数 va_start(var_arg,n_values); for(i=0;i<n_values;++i) { //调用va_arg返回当前可变参数的值,并使变量var_arg指向下一个可变参数 sum+=va_arg(var_arg,int); } //调用va_end将变量var_arg赋空 va_end(var_arg); return sum/n_values; } int main() { float ret=Average(5,2,4,6,7,4); printf("%lf\n",ret); system("pause"); return 0; }即由此可得出和注意项为:
1.va_start两个参数,第一个为va_list变量,第二个为省略号前最后一个有名字的参数,这样才可以通过其地址和类型大小算出可变参数部分的第一个参数地址,来初始化va_list变量;
2.va_arg两个参数,第一个为va_list变量,第二个为下一个可变参数的类型,从而算出当前参数的值和下一个可变参数的地址赋予va_list变量;
3.va_end一个参数为va_list变量,使它指向NULL,不成为野指针。