C语言参数个数可变函数浅析VA函数(variableargumentfunction),参数个数可变函数,又称可变参数函数。C/C++编程中,系统提供给编程人员的va函数很少。*printf()/*scanf()系列函数,用于输入输出时格式化字符串;exec*()系列函数,用于在程序中执行外部文件(main(intargc,char*argv[])算不算呢,与其说main()也是一个可变参数函数,倒不如说它是exec*()经过封装后的具备特殊功能和意义的函数,至少在原理这一级上有很多相似之处)。由于参数个数的不确定,使va函数具有很大的灵活性,易用性,对没有使用过可变参数函数的编程人员很有诱惑力;那么,该如何编写自己的va函数,va函数的运用时机、编译实现又是如何。下面一一介绍。一、从printf()开始从大家都很熟悉的格式化字符串函数开始介绍可变参数函数。原型:intprintf(constchar*format,...);参数format表示如何来格式字符串的指令,…表示可选参数,调用时传递给"..."的参数可有可无,根据实际情况而定。系统提供了vprintf系列格式化字符串的函数,用于编程人员封装自己的I/O函数。intvprintf/vscanf(constchar*format,va_listap);//从标准输入/输出格式化字符串intvfprintf/vfsacanf(FILE*stream,constchar*format,va_listap);//从文件流intvsprintf/vsscanf(char*s,constchar*format,va_listap);//从字符串//例1:格式化到一个文件流,可用于日志文件FILE*logfile;intWriteLog(constchar*format,...){va_listarg_ptr;va_start(arg_ptr,format);intnWrittenBytes=vfprintf(logfile,format,arg_ptr);va_end(arg_ptr);returnnWrittenBytes;}//调用时,与使用printf()没有区别。WriteLog("d-d-dd:d:d%s/dloggedout.",nYear,nMonth,nDay,nHour,nMinute,szUserName,nUserID);同理,也可以从文件中执行格式化输入;或者对标准输入输出,字符串执行格式化。在上面的例1中,WriteLog()函数可以接受参数个数可变的输入,本质上,它的实现需要vprintf()的支持。如何真正实现属于自己的可变参数函数,包括控制每一个传入的可选参数。二、va函数的定义和va宏C语言支持va函数,作为C语言的扩展--C++同样支持va函数,但在C++中并不推荐使用,C++引入的多态性同样可以实现参数个数可变的函数。不过,C++的重载功能毕竟只能是有限多个可以预见的参数个数。比较而言,C中的va函数则可以定义无穷多个相当于C++的重载函数,这方面C++是无能为力的。va函数的优势表现在使用的方便性和易用性上,可以使代码更简洁。C编译器为了统一在不同的硬件架构、硬件平台上的实现,和增加代码的可移植性,提供了一系列宏来屏蔽硬件环境不同带来的差异。ANSIC标准下,va的宏定义在stdarg.h中,它们有:va_list,va_start(),va_arg(),va_end()。//例2:求任意个自然数的平方和:intSqSum(intn1,...){va_listarg_ptr;intnSqSum=0,n=n1;va_start(arg_ptr,n1);while(n>0){nSqSum+=(n*n);n=va_arg(arg_ptr,int);}va_end(arg_ptr);returnnSqSum;}//调用时intnSqSum=SqSum(7,2,7,11,-1);可变参数函数的原型声明格式为:typeVAFunction(typearg1,typearg2,…);参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用"…"表示。固定参数和可选参数公同构成一个函数的参数列表。借助上面这个简单的例2,来看看各个va_xxx的作用。va_listarg_ptr:定义一个指向个数可变的参数列表指针(Linux0.11中为char*类型);va_start(arg_ptr,argN):使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,说明:argN是位于第一个可选参数之前的固定参数,(或者说,最后一个固定参数;…之前的一个参数),函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。如果有一va函数的声明是voidva_test(chara,charb,charc,…),则它的固定参数依次是a,b,c,最后一个固定参数argN为c,因此就是va_start(arg_ptr,c)。va_arg(arg_ptr,type):返回参数列表中指针arg_ptr所指的参数,返回类型为type,并使指针arg_ptr指向参数列表中下一个参数。va_copy(dest,src):dest,s...