摘选自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);
}