zoukankan      html  css  js  c++  java
  • c语言中的可变参数编程

      在c语言中使用变长参数最常见的就是下面两个函数了:

    int printf(const char *format, ...);
    
    int scanf(const char *format, ...);

      那他们是怎样实现支持变成参数的呢?在使用变长参数的函数(这里假设是func)实现部分其实用到了stdarg.h里面的多个宏来访问那些不确定的参数,它们分别是:

    void va_start(va_list ap, last);
    type va_arg(va_list ap, type);
    void va_end(va_list ap);

      假设lastarg是func的最后一个具名参数,即在func函数定义中...之前的那个参数(在printf中lastarg是format),在func中首先定义一个变量:

    va_list ap

      这个变量以后会依次指向各个可变参数。ap在使用之前必须用宏va_start初始化一次,如下所示:

    va_start(ap, lastarg);

    其中lastarg是func中的最后一个具名参数。然后就可以用va_arg来获得下一个不定参数(前提是知道这个不定参数的类型type):

    type next = va_arg(ap, type)

      最后就是用宏va_end来清理现场。

      下面我们来自己实现一个可变参数的函数:

     1 #include <stdio.h>
     2 #include <stdarg.h>
     3 
     4 void func(char *fmt, ...)
     5 {
     6     va_list ap;
     7 
     8     va_start(ap, fmt);
     9 
    10     while (*fmt)
    11     {
    12         switch(*fmt)
    13         {
    14             case 'd':
    15                 fprintf(stdout, "%d\n", (int)va_arg(ap, int));
    16                 break;
    17             case 'c':
    18                 fprintf(stdout, "%c\n", (char)va_arg(ap, int));
    19                 break;
    20             case 's':
    21                 fprintf(stdout, "%s\n", (char *)va_arg(ap, char *));
    22                 break;
    23             default:
    24                 fprintf(stderr, "error fmt\n");
    25         }
    26         fmt ++;
    27     }
    28     va_end(ap);
    29 }
    30 
    31 int main ( int argc, char *argv[] )
    32 {
    33     func("dcs", 10, 's', "hello");
    34     return 0;
    35 }               /* ----------  end of function main  ---------- */

      输出结果:

    10
    s
    hello

      可以看到上面的程序完成按我们的意愿实现了变长参数的访问,通过前面的fmt来控制下一个不定参数的类型。那这三个宏是怎样实现对不定参数访问的呢?下面来看看它们是怎么实现的:

      va_list实际就是一个指向各个不定参数的指针,由于参数的类型是不确定的,所以可以定义va_list为void *或者char *类型,即

    #define va_list void *

      va_start就是将va_list指向函数最后一个具名参数lastarg后面的位置,这个位置就是第一个不定参数。

    #define va_start(ap, lastarg) \
    (ap = (va_list)&lastarg + sizeof(lastarg))

      va_arg获取当前不定参数的值,根据当前参数的类型的大小移动指针指向下一个不定参数。

    #define va_arg(ap, type) \
    (*(type *)((ap += sizeof(type)) - sizeof(type)))

      va_end将指针清0。

    #define va_end(ap) (ap=(va_list)0)

      本质上其实就是靠前面lastarg来控制不定参数的类型,va_list变量来指向不定参数的地址,然后根据lastarg一个一个的获取不定参数。

  • 相关阅读:
    使用XmlDataDocument将数据存储到XML文档
    Dubbo+Nacos 运行异常io.netty.handler.codec.EncoderException: java.lang.NullPointerException
    一、字符串常量Java内部加载
    更高效率,Java快速获取图片尺寸宽高分辨率(支持webp)
    水印宽高比例自适应图片(Java-Thumbnails)
    UEditor 自定义图片视频尺寸校验
    应用宝官方错误日志
    Eclipse使用hibernate插件
    解决Eclipse建立Maven项目后无法建立src/main/java资源文件夹的办法
    [Err] 1022
  • 原文地址:https://www.cnblogs.com/chengxuyuancc/p/3107058.html
Copyright © 2011-2022 走看看