不确定参数列表

摘选自Linux manual 手册.....

STDARG(3)                  Linux Programmer's Manual                 STDARG(3)

NAME

       stdarg, va_start, va_arg, va_end, va_copy - 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 argument last is the name of the last argument before the  variable

       argument list, that is, the last argument of which the calling function

       knows the type.

 

       Because the address of this argument 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 argument 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 argument 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 traversals of the list, each brack‐

       eted  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 arguments are passed in registers, it may be

       necessary for va_start() to allocate memory, store the arguments there,

       and  also an indication of which argument 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.

 

CONFORMING TO

       The  va_start(),  va_arg(),  and  va_end()  macros conform to C89.  C99

       defines the va_copy() macro.

 

NOTES

       These macros are not compatible with the historic macros they  replace.

       A  backward  compatible  version  can  be  found  in  the  include file

       <varargs.h>.

 

       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).

 

EXAMPLE

       The function foo takes a string of format characters and prints out the

       argument associated with each format character based on the type.

 (转载原文链接:http://blog.chinaunix.net/space.php?uid=22566367&do=blog&id=382046)最近,遇到一个c语言的不定参数问题。其实,对于c语言的不定参数问题,只需要三个函数就可以搞定了。这三个函数的头文件是<stdarg.h>,其实下面的三个函数都是一个宏定义(macro)。

    这三个函数是:    void va_start(va_list ap, last);    type va_arg(va_list ap, type);    void va_end(va_list ap);    如果需要进行其他的一些操作,可以查看一下man手册进行查询。    在这三个函数解释之前,先看一个变量va_list,这个变量的类型是什么呢?通过查看内核源代码,一直追踪下去,才发现它的类型是void *类型的。    对于va_start(va_list ap, last)函数,这个函数是用来初始化指针变量ap(va_list类型)的,以后处理参数就是默认从ap处开始处理。last一般为char *传过来参数列表的第一个参数。    对于va_arg(va_list ap, type)函数来说,就是将ap指针按照type类型向后移动,然后取出ap指针所指的那个参数。    对于va_end(va_list ap)一般和va_start(va_list ap, last)配套使用,做一些善后处理的事情。    会不会是通过argp的值来判断的呢?让我们来做个测试::    这里有一个问题,当我们取参数的时候,如何判断我们要取的参数已经取完了?开始我是这么想的,通过va_arg的返回值进行判断,通过查阅资料,都是这么说的,看来我的猜想是对的。当我把程序写出来进行测试的时候,发现不是这样的

#include <stdio.h>

#include <stdarg.h>

 

int sum(const int , ...);

 

int main(void)

{

    printf("The result is:%d\n", sum(10, 9, 8));

    return 0;

}

 

int sum(const int first, ...)

{

    va_list argp;

    int sum = 0;

    int tmp;

 

    va_start(argp, first);

    sum += first;

    printf("%d\n", first);

    while(argp) {

        tmp = va_arg(argp, int);

        printf("%d\n", tmp);

        sum += tmp;

    }

    va_end(argp);

    return sum;

}

    这个程序的执行结果出乎我的意料,出现了段错误。

    至于如何修改这个程序把不定参数取出来,我还是没有找到解决方法。后来,我想到了printf()函数,我查看了它的源代码,其中主要是调用了vsprintf()函数,至于为什么调用vsprintf()函数,我想可能是为了实现类似于fprintf()之类的函数调用的方便,这样也提高了函数的利用率。printf()函数的主要代码:

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

       }

 #include<stdio.h>

#include<stdarg.h>//要包含这个头文件,其中有va_list 等的声明(va_list 貌似是一个char *类型(或者是void*)

 

void foo(int ,...);

 

int main(void)

{

    foo(4,1,2,3,5);

 

    return 0;

}

 

void foo(int a,...)            //这里我把函数的第一个参数放到a中....

{

    int num;

    va_list l;                  //定义一个va_list结构

    va_start(l,a);              //初始化 l

    while(a--)

    {

        num=va_arg(l,int);      //取出参数

        printf("%d\n",num);

    }

    va_end(l);

 

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值