详解stdarg.h文件(可变参数函数的操作)

作用:
       可变参数的操作

概要:
       #include <stdarg.h>


       void va_start(va_list ap, last);
       type va_arg(va_list ap, type);
       void va_end(va_list ap);
       void va_copy(va_list dest, va_list src);


描述:

      函数的参数可能会是不同类型的可变参数。头文件<stdarg.h>中声明了va_list及定义了三个宏定义,用于遍历被调函数中未知的参数个数及类型。


      调用该可变参数必须先声明一个va_list对象,这个对象可用va_start(),va_arg(),va_end()这三个宏来操作。

va_start()


       宏va_start() 初始化了参数ap,该宏必须最先调用,之后才能调用va_arg(),va_end()。


      参数last是参数列表中的第一个参数,这个参数类型已知。


       因为last遍历可能被用在va_start()中,因此不能定义为register变量、函数或者是一个数组类型。 


   va_arg()

     

       va_arg()展开后有下一个参数的类型和值。参数ap是va_list中的参数,由va_start()初始化。每次调用va_arg()都会修改ap的值,即将ap移动到下一个参数处。参数type必须是指定的参数,可以是指针类型。


      第一次调用该宏时将返回参数last之后的参数,连续调用返回剩余的参数。

      如果没有下一个参数了,或者实际类型跟参数type不匹配,将会发生随机错误。

      经测试,type类型不能是char或者short类型!

      如果使用va_arg(ap,type)将ap传到另一个函数,那么在返回该函数后ap将被释放。


va_end()

       每次调用va_end()时,必须要在同一函数先调用与之相对的va_end()。调用va_end(ap)后,ap将变成未定义。多个遍历列表中,成对出现va_start()和va_end()是可能的,va_end()可能是一个宏或者是一个函数。


va_copy()

宏va_copy()可以从源参数列表中复制参数值到已初始化的变量中。

va_list aq = ap;

系统会复制来的参数保存到一个指针数组中
va_list aq;
*aq = *ap;
       
上述赋值也可写成:
va_list aq;
va_copy(aq, ap);
...
va_end(aq);

每次调用完va_copy()后,必须在同一函数中调用va_end()。某些系统中可能不支持va_copy(),可用 __va_copy()替代。


特征:
  
       va_start(), va_arg(), va_end(), and va_copy() 宏是线程安全的(thread-safe)

注:
       The  va_start(),  va_arg(),  和va_end() 确定于C89。C99定义了宏va_copy()


注2:

       这些宏不兼容历史版本。历史版本可在<varargs.h>中找到。


先前的版本配置如下:

   
 #include <varargs.h>

void
foo(va_alist)
va_dcl
{
     va_list ap;
     va_start(ap);
     while (...) {
        ...
        x = va_arg(ap, type);
         ...
      }
      va_end(ap);
 }

在某些系统中,va_end包含一个关闭符号“}”,匹配与va_start()的开始符号“{”.因此这两个函数必须成对出现在一个函数中


BUGS

不像varargs宏,宏stdarg不允许写一个不匹配的参数的函数。即当将varargs代码转换为stdarg代码就会出问题



示例:

#include <stdio.h>
#include <stdarg.h>

void foo(char *fmt, ...)
{
    va_list ap;
    int d;
    char c, *s;

    va_start(ap, fmt);
    while (*fmt)
       switch (*fmt++) {
           case 's':              /* string */
              s = va_arg(ap, char *);
              printf("string %s\n", s);
              break;
           case 'd':              /* int */
              d = va_arg(ap, int);
              printf("int %d\n", d);
              break;
           case 'c':              /* char */
              /* need a cast here since va_arg only
              takes fully promoted types */
              c = (char) va_arg(ap, int);
              printf("char %c\n", c);
              break;
       }
       va_end(ap);
 }



该头文件的最新版本,可参见http://www.kernel.org/doc/man-pages/

以上内容翻译自debian 8系统中man va_arg命令



相关推荐
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页