1、应用与原理
在C语言中又是我们无法给出一个函数参数的列表,比如:
这是我们使用到了可以变参数,也就是使用...代表0个或多个参数。 那么编译器如何获取/使用这些参数。这涉及到参数的传递原理: 参数传递原理: 在内存中,函数的参数以栈的方式存取,从右到左入栈。这些参数存放的地址是连续的。这样,我们就可以通过获取第一个参数的地址,以及各个参数的地址偏移量,就可以获取每个参数的地址,从而得到每一个参数。int printf(const char *format, ...);int fprintf(FILE *stream, const char *format, ...);
2、va_start、va_arg、va_end、va_copy介绍
va_list是一个指向参数首地址的指针,#includevoid 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);
va_start 对ap进行了一系列的初始化,之后ap会被va_arg和va_end使用到。last是可变参数...的前一个参数,如fun(char *fmt, ...) 中的fmt。通过va_start初始化ap,我们就获得了可变参数前一个参数fmt的地址。 va_argtypedef struct {char *a0; /* pointer to first homed integer argument */int offset; /* byte offset of next parameter */} va_list;
va_arg用于获取可变参数...的每一个参数。如函数fun(char *fmt, ...)的一次调用fun(fmt, arg1, arg2, arg3)。在使用va_start()进行ap的初始化后,我们调用一次va_arg(ap,type)就获得了参数arg1,在调用一次就获得arg2,……从而,得到每一个参数的值。
va_end va_end用于清理ap的值,与va_start()配对使用。 va_copy 不常用,暂不介绍。
3、Example
先给一个man手册里的例子//foo.c#include#includevoidfoo(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/* need a cast here since va_arg onlytakes fully promoted types */c = (char) va_arg(ap, int);printf("char %c\n", c);break;}va_end(ap);}
执行结果://main.c#include#include#include "foo.h"intmain(void){foo("%s %d %c %d %c", "Hello", 4, 'x', 3, 'y');return 0;}
使用vsprintf的例子windeal@ubuntu:~/Windeal/apue$ ./exestring Helloint 4char xint 3char ywindeal@ubuntu:~/Windeal/apue$
//foo.c#include#includevoidfoo(char *fmt, ...){va_list ap;int len = 0;char buf[64];va_start(ap, fmt);len = vsnprintf(buf, 128, fmt, ap);va_end(ap);int i = 0;for(i = 0; i < len; i++){putchar(buf[i]);}return ;}~
执行结果:// main.c#include#include#include "foo.h"intmain(void){foo("Test:%s %d %c %d %c\n", "Hello", 4, 'x', 3, 'y');return 0;}
windeal@ubuntu:~/Windeal/apue$ ./exeTest:Hello 4 x 3 y