c函数参数怎么用(可变参数列表CC)
c函数参数怎么用(可变参数列表CC)#elif defined(_M_IX86) #define _INTsizeof(n) ( (sizeof(n) sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap v) ( ap = (va_list)_ADDRESSOF(v) _INTSIZEOF(v) ) #define _crt_va_arg(ap t) ( *(t *)((ap = _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 ) #elif defined(_M_IA64)很明显va_list就是一个类型重命名;va_list实际上就是char*型,简言之va_list arg就是声明了一个字符型指针ar
可变参数列表:
在我们一般经常使用的函数中,函数列出了期望接受的参数,但函数原型只能显示固定的参数,那么,如何让一个函数在不同的时候接受不同数目的参数呢!使用可变参数列表就可实现,当一个函数事先不确定有多少个参数但是可以接受一个或多个参数,可以使得函数可以接受1个以上的任意多个参数。
可变参数列表是通过宏来实现的,这些宏定义在stdarg.h头文件中,在这个头文件中声明了 一个类型va_list和三个宏va_start、va_arg、va_end配合使用,访问参数的值。
可变参数函数的原型声明格式为:type VAFunction(type arg1 type arg2 … ); 参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用"…"表示。固定参数和可选参数共同构成一个函数的参数列表。
举个例子理解:比方求指定个数的平均值
#include <stdio.h>
#include <stdarg.h>
int average(int n ...) //定义一个函数,实现可变参数
{
va_list arg; //定义一个变量arg为va_list类型
int i = 0;
int sum = 0;
va_start(arg n);
for(i=0; i<n; i ) //循环获取参数
{
sum = va_arg(arg int);
}
return sum/n;
va_end(arg);
}
int main()
{
int ret1 = 0;
int ret2 = 0;
ret1 = average(3 1 2 3);
ret2 = average(4 2 3 3 5);
printf("%d\n" ret1);
printf("%d\n" ret2);
return 0;
}
程序结果
在vs中我们可以转到定义处查看各个类型和宏具体是怎样实现的
1、首先va_list arg;
#elif defined(_M_IX86)
#define _INTsizeof(n) ( (sizeof(n) sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_start(ap v) ( ap = (va_list)_ADDRESSOF(v) _INTSIZEOF(v) )
#define _crt_va_arg(ap t) ( *(t *)((ap = _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_IA64)
很明显va_list就是一个类型重命名;va_list实际上就是char*型,简言之va_list arg就是声明了一个字符型指针arg。
2、va_start(arg n);
#elif defined(_M_IX86)
#define _INTSIZEOF(n) ( (sizeof(n) sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_start(ap v) ( ap = (va_list)_ADDRESSOF(v) _INTSIZEOF(v) )
#define _crt_va_arg(ap t) ( *(t *)((ap = _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_IA64)
_INTSIZEOF(n)整个做的事情就是将n的长度化为int长度的整数倍
va_srart(ap v)就是把上面的字符指针向后移动,跳过第一个参数n的地址。
3、va_arg(args int)
#define _crt_va_end(ap) ( ap = (va_list)0 )
va_arg(args int) 就是循环获取到可变参数列表中的参数,args指向下一个参数地址,返回的则是当前参数地址。
4、va_end(arg);
#define _crt_va_end(ap) ( ap = (va_list)0 )
当访问完毕最后一个参数时,用VA_END宏结束可变参数的获取。
可变参数列表的缺陷:
1、可变参数必须从头到尾逐个访问。如果你在访问了几个可变参数之后想半途
终止,这是可以的,但是,如果你想一开始就访问参数列表中间的参数,那
是不行的
2、参数列表中至少有一个命名参数。如果连一个命名参数都没有,就无法使用
va_start。
3、如果在va_arg中指定了错误的类型,结果无法预测,因为在使用时,char、short、float类型的值实际上都作为int或double类型的值传递给函数。