一、在介绍va_list之前,首先介绍众所周知的printf()函数的实现,请看下面的代码:


int printf(char const* __restrict fmt,...)
{
	va_list arg_ptr;
	
	va_start(arg_ptr,fmt);
	
	int ret = vfprintf(stdout,fmt,arg_ptr);

	va_end(arg_ptr);

	return ret;
}

printf函数的形参列表长度是可变的,这种函数被称为变参函数,即参数的个数不确定。相比C++中的重载中对参数的个数的限制,变参函数使用起来比较灵活。


下面看下该函数是如何显现的。其主要使用的va_list类型才使得printf函数具有如此的灵活性。所以printf的使用灵活性应归功于va_list。


二、可变参函数的声明

在无法给出所有传递给函数的参数的类型和数目时,可以使用省略号(...)指定函数参数表。有如下几种形式:


1 void fun1(int a, double b, ...); //给出确定的几个参数,其他用省略号
	2 void fun2(int a ...);            //省略号前有或者没有逗号都是可以的
	3 void fun3(...);                  //也可以不确定任何参数,但和没有参数是不一样的



三、va_start,va_arg,va_end三个宏的介绍:


下面三个宏是来调用操作可变参数:

#include <stdarg.h>

	void va_start(
 	 	 va_list arg_ptr, //指向参数列表的指针
   				prev_param 	   //最后一个显式声明的参数,以用来获取第一个可变参数的位置
	);

	type va_arg( 	 
	 	va_list arg_ptr,  	
	 			type  //要获取的参数类型,如char,int,float等
	);		

	void va_end(
 	 	 va_list arg_ptr 
	);

四、va_start,va_arg,va_end三个宏的使用:


1、定义一个va_list变量,该变量是指向可变参数的指针。

2、使用va_start初始化刚刚声明的va_list变量。第二个参数是可变参数最后一个显式声明的参数。

3、使用va_arg返回可变参数的值,第二个参数是该可变参数的类型。注意需要确定va_list变量是否是指向你想要的变量。

4、使用va_end清空第一步声明的va_list变量为NULL.


注意:1、可变参数的类型和数目不能通过这三个宏来获取,只能通过程序来控制。



五、具体使用详见第一部分的printf函数的实现。


六、关于va_list和这三个宏是如何定义,请自行查看MFC中头文件stdio.h,stdarg.h。当然不用的编译器,有不同的定义。