C语言中的 stdarg - variable argument lists

97 篇文章 0 订阅
40 篇文章 0 订阅

C语言中处理函数可变参数的几个宏:stdarg


一、stdarg 简介:

在编写程序时,有时会遇到可变参数个数的函数,这种函数一般都使用了stdarg.h这个头文件中的几个宏。

下面给出 Linux manual 中的介绍。

NAME  

       stdarg - variable argument lists  

名称

stdarg-variable argument lists               // stdarg :可变参数列表。



SYNOPSIS
       #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);


概要 

      #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的描述

DESCRIPTION      //描述

       A  function may be called with a varying number of arguments of varying
       types.  The include file <stdarg.h> declares a type va_list and defines
       three  macros for stepping through a list of arguments whose number and
       types are not known to the called function.


一个参数类型和参数个数都不确定(变化)的函数可能被调用。在include <stdarg.h> 文件中,声明了一个va_list类型,并且定义了3个宏 (macro)用来遍历对一个参数列表,但这个参数列表中的参数的类型和参数的个数都是不确定的,在这个可变参数的函数被调用前。


       The called function must declare an object of  type  va_list  which  is

       used by the macros va_start(), va_arg(), and va_end().

     这个被调用的可变参数函数  必须声明一个va_list类型的的对象,因为宏 va_start(), va_arg(),和va_end()使用这个对象。



   1. 宏 va_start

       void va_start(va_list ap, last);    

       The  va_start() macro initializes ap for subsequent use by va_arg() and   va_end(), and must be called first.

        宏va_start() 必须被首先调用; 其初始化ap对象,ap对象,将在后续的宏va_arg(), va_end()宏调用中使用。


       The parameter last is the name of the last parameter before  the  variable argument list, i.e., the last parameter of which the calling func
tion knows the type.
       参数last 是变参数列表前的最后一个参数的名字(变量名),也就是说函数所能确定的参数中的最后一个。

       Because the address of this parameter may be  used  in  the  va_start() macro,  it should not be declared as a register variable, or as a function or an array type.
      因为这个参数的地址在宏va_start()中可能被用到,所以它不能被声明为寄存器变量,或者函数、数组类型。

   2. 宏 va_arg

     type va_arg(va_list ap, type);

       The va_arg() macro expands to an expression that has the type and value of  the  next argument in the call.  The parameter ap is the va_list ap  initialized by va_start().  Each call to va_arg() modifies ap  so  that  the  next call returns the next argument.  The parameter type is a type name specified so that the type of a pointer to an object that has  the specified type can be obtained simply by adding a * to type.

      宏va_arg() 将函数未知参数列表中的下一个参数扩展为具有的值和类型的一个表达式。 参数ap 是被va_start()初始化的 va_list ap.

每一次调用va_arg 都修改ap的值,以致下次调用返回下一个参数的值。 参数type是一个指定的类型,因此指向这中类型的对象的指针能够简单获得通过*(dereference)获得这种类型。


       The  first use of the va_arg() macro after that of the va_start() macro returns the argument after last.   Successive  invocations  return  the values of the remaining arguments.

 在使用了宏va_start(ap, last)之后,首次使用宏va_arg(ap, type) ,返回紧接着last的那个参数的值。后继的调用,返回剩余参数的值。

       If  there  is  no  next argument, or if type is not compatible with the  type of the actual next argument (as promoted according to the  default  argument promotions), random errors will occur.

     如果,没有下一个参数,或者类型与下一个参数的类型不兼容(声明的类型与参数的默认类型),不确定的错误将发生。


       If  ap is passed to a function that uses va_arg(ap,type) then the value of ap is undefined after the return of that function.

       如果 ap 传递给一个使用了va_arg(ap, type)函数 ,那么ap的值在函数返回后将是不确定的,



  3. 宏 va_end

      void va_end(va_list ap);

       Each invocation of va_start() must be matched by a corresponding  invocation  of va_end() in the same function. After the call va_end(ap) the variable ap is undefined.  Multiple  transversals  of  the  list,  each  bracketed  by  va_start() and va_end() are possible.  va_end() may be a  macro or a function.

 在同一个函数中,每一次调用va_start() 都必须有一个va_end调用语气配对. 在调用va_end(ap) 后,ap的值将是不确定的。多次遍历参数列表时,每次都要以va_start(ap, last)开始,以va_end(ap)结束,才是可行的。

va_end(ap) 可能是个函数,也可能是个宏。


4. 宏  va_copy

      void va_copy(va_list dest, va_list src);

       An obvious implementation would have a va_list  be  a  pointer  to  the stack frame of the variadic function.  In such a setup (by far the most common) there seems nothing against an assignment
                   va_list aq = ap;
       Unfortunately, there are also systems that make it an array of pointers  (of length 1), and there one needs
                   va_list aq;
                   *aq = *ap;
       Finally, on systems where parameters are passed in registers, it may be necessary for va_start()  to  allocate  memory,  store  the  parameters there,  and  also  an  indication  of  which parameter is next, so that  va_arg() can step through the list. Now va_end() can free the allocated  memory  again.   To  accommodate  this  situation,  C99  adds  a  macro va_copy(), so that the above assignment can be replaced by
                   va_list aq;
                   va_copy(aq, ap);
                   ...
                   va_end(aq);
       Each invocation of va_copy() must be matched by a corresponding invoca tion of va_end() in the same function.  Some systems that do not supply  va_copy() have __va_copy instead, since that was the name used  in  the draft proposal.


EXAMPLE
       The function foo takes a string of format characters and prints out the
       argument associated with each format character based on the type.
              #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);
              }


CONFORMING TO
       The va_start(), va_arg(), and va_end()  macros  conform  to  C89.   C99 defines the va_copy() macro.


COMPATIBILITY
       These  macros are not compatible with the historic macros they replace.  A backward  compatible  version  can  be  found  in  the  include  file  varargs.h.


COMPARISON
       The historic setup is:
              #include <varargs.h>

              void foo(va_alist) va_dcl {
                   va_list ap;


                   va_start(ap);
                   while(...) {
                        ...
                        x = va_arg(ap, type);
                        ...
                   }
                   va_end(ap);
              }
       On  some  systems,  va_end  contains  a  closing  ’}’ matching a ’{’ in va_start, so that both macros must occur in the same function, and in a  way that allows this.


BUGS
       Unlike  the varargs macros, the stdarg macros do not permit programmers to code a function with no fixed  arguments.   This  problem  generates work  mainly  when  converting varargs code to stdarg code, but it also creates difficulties for variadic functions that wish to  pass  all  of  their arguments on to a function that takes a va_list argument, such as  vfprintf(3).


Linux manual 手册介绍:

[wzb@embedded test]$ man stdarg | cat
STDARG(3)                  Linux Programmer’s Manual                 STDARG(3)



NAME
       stdarg - variable argument lists

SYNOPSIS
       #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);

DESCRIPTION
       A  function may be called with a varying number of arguments of varying
       types.  The include file <stdarg.h> declares a type va_list and defines
       three  macros for stepping through a list of arguments whose number and
       types are not known to the called function.

       The called function must declare an object of  type  va_list  which  is
       used by the macros va_start(), va_arg(), and va_end().

   va_start
       The  va_start() macro initializes ap for subsequent use by va_arg() and
       va_end(), and must be called first.

       The parameter last is the name of the last parameter before  the  vari-
       able argument list, i.e., the last parameter of which the calling func-
       tion knows the type.

       Because the address of this parameter may be  used  in  the  va_start()
       macro,  it should not be declared as a register variable, or as a func-
       tion or an array type.

   va_arg
       The va_arg() macro expands to an expression that has the type and value
       of  the  next argument in the call.  The parameter ap is the va_list ap
       initialized by va_start().  Each call to va_arg() modifies ap  so  that
       the  next call returns the next argument.  The parameter type is a type
       name specified so that the type of a pointer to an object that has  the
       specified type can be obtained simply by adding a * to type.

       The  first use of the va_arg() macro after that of the va_start() macro
       returns the argument after last.   Successive  invocations  return  the
       values of the remaining arguments.

       If  there  is  no  next argument, or if type is not compatible with the
       type of the actual next argument (as promoted according to the  default
       argument promotions), random errors will occur.

       If  ap is passed to a function that uses va_arg(ap,type) then the value
       of ap is undefined after the return of that function.

   va_end
       Each invocation of va_start() must be matched by a corresponding  invo-
       cation  of va_end() in the same function. After the call va_end(ap) the
       variable ap is undefined.  Multiple  transversals  of  the  list,  each
       bracketed  by  va_start() and va_end() are possible.  va_end() may be a
       macro or a function.

   va_copy
       An obvious implementation would have a va_list  be  a  pointer  to  the
       stack frame of the variadic function.  In such a setup (by far the most
       common) there seems nothing against an assignment
                   va_list aq = ap;
       Unfortunately, there are also systems that make it an array of pointers
       (of length 1), and there one needs
                   va_list aq;
                   *aq = *ap;
       Finally, on systems where parameters are passed in registers, it may be
       necessary for va_start()  to  allocate  memory,  store  the  parameters
       there,  and  also  an  indication  of  which parameter is next, so that
       va_arg() can step through the list. Now va_end() can free the allocated
       memory  again.   To  accommodate  this  situation,  C99  adds  a  macro
       va_copy(), so that the above assignment can be replaced by
                   va_list aq;
                   va_copy(aq, ap);
                   ...
                   va_end(aq);
       Each invocation of va_copy() must be matched by a corresponding invoca-
       tion of va_end() in the same function.  Some systems that do not supply
       va_copy() have __va_copy instead, since that was the name used  in  the
       draft proposal.

EXAMPLE
       The function foo takes a string of format characters and prints out the
       argument associated with each format character based on the type.
              #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);
              }

CONFORMING TO
       The va_start(), va_arg(), and va_end()  macros  conform  to  C89.   C99
       defines the va_copy() macro.

COMPATIBILITY
       These  macros are not compatible with the historic macros they replace.
       A backward  compatible  version  can  be  found  in  the  include  file
       varargs.h.

COMPARISON
       The historic setup is:
              #include <varargs.h>

              void foo(va_alist) va_dcl {
                   va_list ap;

                   va_start(ap);
                   while(...) {
                        ...
                        x = va_arg(ap, type);
                        ...
                   }
                   va_end(ap);
              }
       On  some  systems,  va_end  contains  a  closing  ’}’ matching a ’{’ in
       va_start, so that both macros must occur in the same function, and in a
       way that allows this.

BUGS
       Unlike  the varargs macros, the stdarg macros do not permit programmers
       to code a function with no fixed  arguments.   This  problem  generates
       work  mainly  when  converting varargs code to stdarg code, but it also
       creates difficulties for variadic functions that wish to  pass  all  of
       their arguments on to a function that takes a va_list argument, such as
       vfprintf(3).



                                  2001-10-14                         STDARG(3)




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值