zoukankan      html  css  js  c++  java
  • va_start、va_arg、va_end、va_copy 可变参函数


    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>
    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
    ", s);
               break;
           case 'd':              /* int */
               d = va_arg(ap, int);
               printf("int %d
    ", 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
    ", c);
               break;
           }
       va_end(ap);
    }

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


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


    使用vsprintf的例子
    //foo.c
    #include <stdarg.h>
    #include <stdio.h>
    void
    foo(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"
    int
    main(void)
    {
            foo("Test:%s %d %c %d %c
    ", "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 可变参函数

  • 相关阅读:
    《社区教育在线学习平台评价体系的设计研究》 文献随笔(七)
    《基于个性化推荐的在线学习系统研究与实现》 文献随笔(六)
    《基于校园网云平台微课在线学习系统的设计分析》 文献随笔(五)
    《基于微服务架构的在线学习系统设计与实现》第三章 文献随笔(四)
    《基于微服务架构的在线学习系统设计与实现》第一章节5 文献笔记(三)
    《基于Android的微课程平台设计》论文笔记(二)
    《基于Android的在线学习软件的设计与实现》论文笔记一
    在线学习系统的设计与实现 文献综述
    《基于JavaEE的全丰集团OA系统的设计与实现》论文笔记(十六)
    《电子签名技术在 OA 系统公文流转中的应用》论文笔记(十五)
  • 原文地址:https://www.cnblogs.com/Windeal/p/4284636.html
Copyright © 2011-2022 走看看