当无法列出函数所有形参的类型和数目时,可用省略号指定参数表,例如:
void foo(...);
void foo(parm_list,...);
下面介绍这种可变参数列表的函数该如何处理传递来的参数。
1. 函数参数的传递原理
函数参数是以数据结构——栈的形式存取,参数从右至左入栈。eg:
void func(int x, float y, char z);
调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z。因此,从理论上说,只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,总可以找到其他的输入变量。
2. 处理可变参数列表的宏
在<stdarg.h> 里定义了几个重要的处理可变参数列表的宏:
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是一个字符指针类型,用于定义指向省略号"..." 所代表的参数列表的指针,如定义:
va_list ap;
va_start 用于初始化上面定义的指针,使其指向"..." 参数列表的起始地址,va_start的第二个
参数就是邻近"..." 参数列表的参数,用于定位"..." 参数列表;
va_arg 用于获取参数,它的第一个参数是ap,第二个参数是要获取的参数的指定类型,然后返回
这个指定类型的值,并且把 ap 的位置指向变参表的下一个变量位置;
va_end 将参数ap 置为 NULL,关闭指针,以免产生悬指针。
3. 示例
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
va_list args;
va_start(args, pszFormat); //一定是邻近“...”的那个参数
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
}
例中函数_vsnprintf用于输出 "..." 列表参数,其说明如下:
头文件
#include <stdarg.h>
函数声明:
int _vsnprintf(char *buffer, size_t max_count, const char *format, va_list vArgList);
参数说明:
1). char *buffer [out],把生成的格式化的字符串存放在这里.
2). size_t max_count [in], buffer可接受的最大字节数,防止产生数组越界.
3). const char *format [in], 格式化字符串
4). va_list vArgList [in], va_list变量. va:variable-argument:可变参数
用法类似于vsprintf,只不过加了max_count的限制.
返回值说明:
如果成功调用此函数,返回写到buffer中的字符的个数(不包括结尾的'\0')。snprintf和vsnprintf函数不能够写多于size大小(包括结尾的'0')的字节数。如果输出因为以上原因被截断,返回成功写入buffer的字符数(不包括结尾的'\0'),如果有足够的内存空间的话。所以,如果返回值等于size或者大于size,表示输出到buffer的字符被截断,如果输出过程中遇到错误,则返回一个负数。