头文件<stdarg.h>声明了一种类型并且定义了三个宏,这样就可以提前访问一个参数表,调用函数在被编译时并不知道这个参数表中参数的数目和类型。其目的是是为了让函数能够接受可变参数。
1、类型:va_list
它是一个保存宏va_start、va_arg和va_end所需要的信息的类型。如果要访问不同的参数,那么调用的函数要声明一个va_list类型的数据对象(假设该数据对象名为ap)。对象ap可能作为参数传递给另一个函数。如果那个函数对参数ap调用宏va_arg,那么ap在调用函数中的值是不确定的,而且在其他队ap的引用之前会把它传递给宏va_end。
2、宏:
void va_start(va_list ap,paramN);
说明:要在访问所有未命名的参数之前调用宏va_start。宏va_start对ap进行初始化,以便后面va_arg和va_end对它使用。
参数:parmN是函数定义的可变参数表中最右边参数的标识符。
返回值:宏va_start没有返回值。
type va_arg(va_list ap,type);
说明:宏va_arg展开为一个表达式,这个表达式的类型和跟调用的下一个参数的相同。
参数:参数ap应该和va_start初始化的va_list ap相同,va_arg的每一次调用都会修改ap。type是指定类型名字,使得指向指定类型的数据对象的指针的类型可以简单的通过在类型后面加一个*来获得。
返回值:第一个调用va_start后,对va_arg的第一次调用返回的是parmN指定参数后面的参数值。后面的调用一次返回剩下的参数值。
void va_end(va_list ap);
说明:宏va_end促进函数的正常返回,该函数的可变参数表被初始化了va_list ap的va_start的扩展所引起。
返回值:宏va_end没有返回值。
例:
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
typedef struct{
char c;
}Cstruct;
static int tryit(const char *fmt,...)
{
int ctr=0;
va_list ap;
va_start(ap,fmt);
for(;*fmt;++fmt)
{
switch(*fmt)
{
case ‘i‘:
assert(va_arg(ap,int)==++ctr);
break;
case ‘d‘:
assert(va_arg(ap,double)==++ctr);
break;
case ‘p‘:
assert(va_arg(ap,char *)[0]==++ctr);
break;
case ‘s‘:
assert(va_arg(ap,Cstruct).c==++ctr);
}
}
va_end(ap);
return (ctr);
}
int main()
{
Cstruct x={3};
assert(tryit("ai",‘i‘)==0);
printf("success testing <stdarg.h>\n");
return (0);
}