<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /> 
基本知识:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

   我们经常在LINUX代码中看到传递不定参数的函数,这是怎样实现的呢?

    我们可以通过在头文件stdarg.h中定义的va_start(), va_arg(),va_end()这几个函数来实现。在/opt/buildroot-gcc342/lib/gcc/mipsel-linux-uclibc/<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />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 <stdio.h> 

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_list            vargs;
       char_t            *buf;
       int                  rc;

 

       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 <stdio.h>
#include <string.h>
#include <stdarg.h>
/* 函数原型声明,至少需要一个确定的参数,注意括号内的省略号 */
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;
       }
运行结果: