基本知识:
我们经常在LINUX代码中看到传递不定参数的函数,这是怎样实现的呢?
我们可以通过在头文件stdarg.h中定义的va_start(), va_arg(),va_end()这几个函数来实现。在/opt/buildroot-gcc342/lib/gcc/mipsel-linux-uclibc/3.4.2/include目录下找到了stdarg.h,值得注意的是,这三个函数是在gcc编译器中定义的,而不是内核或C库中的定义的。
它们的作用是:
va_start
使argp指向第一个可选参数。注意是第一个可选参数,而不是第一个参数。
va_arg
返回参数列表中的当前参数并使argp指向参数列表中的下一个参数。
va_end
把argp指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。
基本原理
关于stdarg.h中的定义,我并没有去深究。我想其基本原理可以用下面的这段代码来说明。
#include
void fun(int a, ...)
{
int *temp = &a;
temp++;
int i=0;
for(i = 0; i < a; ++i)
{
printf("%d\n", *temp);
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun(4, a, b, c, d);
return 0;
}
stdarg.h与上面代码不同之处,我的理解是,va_start,和va_end的作用,有点像进入临界区的意思,在这个临界区内,不允许其他进程的内存操作。
应用实例
例如,在我们是实际应用中goahead开源软件中用到的这段代码:
int websWrite(webs_t wp, char_t *fmt, ...)
{
va_listvargs;
char_t*buf;
intrc;
a_assert(websValid(wp));
va_start(vargs, fmt);
buf = NULL;
rc = 0;
if (fmtValloc(&buf, WEBS_BUFSIZE, fmt, vargs) >= WEBS_BUFSIZE) {
trace(0, T("webs: websWrite lost data, buffer overflow\n"));
}
va_end(vargs);
a_assert(buf);
if (buf) {
rc = websWriteBlock(wp, buf, gstrlen(buf));
bfree(B_L, buf);
}
return rc;
}
下面再给个例子。
#include
#include
#include
/*函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/
int demo(char[], ...);
int main(void)
{
demo("DEMO", "This", "is","a", "demo!", "");
return 0;
}
/*ANSI标准形式的声明方式,括号内的省略号表示可选参数*/
int demo(char msg[], ... )
{
/*定义保存函数参数的结构*/
va_list argp;
int argno = 0;
char *para;
/*argp指向传入的第一个可选参数,msg是最后一个确定的参数*/
va_start(argp, msg );
while (1)
{
para = va_arg( argp, char *);
if ( strcmp( para, "") == 0 )
break;
printf("Parameter #%d is:%s\n",argno,para);
argno++;
}
va_end( argp );
/*将argp置为NULL*/
return 0;
}
运行结果: