浅析可变参数列表

可变参数列表:

      在我们一般经常使用的函数中,函数列出了期望接受的参数,但函数原型只能显示固定的参数,那么,如何让一个函数在不同的时候接受不同数目的参数呢!使用可变参数列表就可实现,当一个函数事先不确定有多少个参数但是可以接受一个或多个参数,可以使得函数可以接受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;

#ifndef _VA_LIST_DEFINED
#ifdef _M_CEE_PURE
typedef System::ArgIterator va_list;
#else
typedef char *  va_list;
#endif /* _M_CEE_PURE */
#define _VA_LIST_DEFINED
#endif

很明显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_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

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类型的值传递给函数。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值