va_start、va_arg、va_end、va_copy 可变参函数

来源:互联网 发布:比较骚的网络女主播 编辑:程序博客网 时间:2024/06/06 05:34


1、应用与原理

        在C语言中,有时我们无法给出一个函数参数的列表,比如:
  int printf(const char *format, ...);  int fprintf(FILE *stream, const char *format, ...);

    这时我们使用到了可以变参数,也就是使用...代表0个或多个参数。
    那么编译器如何获取/使用这些参数。这涉及到参数的传递原理:
参数传递原理:
    在内存中,函数的参数以栈的方式存取,从右到左入栈。这些参数存放的地址是连续的。这样,我们就可以通过获取第一个参数的地址,以及各个参数的地址偏移量,就可以获取每个参数的地址,从而得到每一个参数。

2、va_start、va_arg、va_end、va_copy介绍

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

va_list是一个指向参数首地址的指针,
typedef struct {char *a0; /* pointer to first homed integer argument */int offset; /* byte offset of next parameter */} va_list;

va_start     
        对ap进行了一系列的初始化,之后ap会被va_arg和va_end使用到。last是可变参数...的前一个参数,如fun(char *fmt, ...)   的fmt。通过va_start初始化ap,我们就获得了可变参数前一个参数fmt的地址。
va_arg   
        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 <stdarg.h>#include <stdio.h>voidfoo(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 only              takes fully promoted types */           c = (char) va_arg(ap, int);           printf("char %c\n", c);           break;       }   va_end(ap);}

//main.c#include <stdio.h>#include <stdarg.h>#include "foo.h"intmain(void){        foo("%s %d %c %d %c", "Hello", 4, 'x', 3, 'y');        return 0;}


执行结果:
windeal@ubuntu:~/Windeal/apue$ ./exe string Helloint 4char xint 3char ywindeal@ubuntu:~/Windeal/apue$


使用vsprintf的例子
//foo.c#include <stdarg.h>#include <stdio.h>voidfoo(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 <stdio.h>#include <stdarg.h>#include "foo.h"intmain(void){        foo("Test:%s %d %c %d %c\n", "Hello", 4, 'x', 3, 'y');        return 0;}


执行结果:
windeal@ubuntu:~/Windeal/apue$ ./exe Test:Hello 4 x 3 y

































va_start、va_arg、va_end、va_copy 可变参函数va_start、va_arg、va_end、va_copy 可变参函数

0 0
原创粉丝点击