zoukankan      html  css  js  c++  java
  • 读书笔记:c语言标准库

    · 变长参数(stdarg.h)

      变长参数是c语言的特殊参数形式,例如如下函数声明:

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

      如此的声明表明,printf函数除了第一个参数类型为const char*之外,其后可以追加任意数量、任意类型的参数。

      在函数实现部分,可以使用stdarg.h里的多个宏来访问各个额外的参数:假设lastarg是变长参数函数的最后一个具名参数(printf里的format),那么在函数内容定义类型为va_list的变量:

    va_list ap;
    

      该变量以后将会依次指向各个可变参数,ap必须用宏va_start初始化一次,其中lastarg必须是函数的最后一个具名的参数。

    va_start(ap,lastarg);
    

      以后,可以使用va_arg宏来获取下一个不定参数(假设已知其类型为type):

    type next = va_arg(ap, type);
    

      在函数结束前,还必须用宏va_end来清理现场。

    整理:

      va_list  实际是一个指针,用来指向各个不定参数。由于类型不明,因此这个va_lish以void *或者char *为最佳选择;

      va_start 将va_list定义的指针指向函数的最后一个参数后面的位置,这个位置就是第一个不定参数;

      va_arg   获取当前不定参数的支,并根据当前不定参数的大小将指针指向下一个参数;

      va_end  将指针清0。

      按照以上思路,va系列宏的一个最简单的实现就可以得到如下:

    #define va_list char*
    #define va_start (ap,arg)  (ap = (va_list)&arg + sizeof(arg))
    #define va_arg(ap,t)  (*(t*)((ap+=sizeof(t) - sizeof(t)))
    #define va_end(ap)  (ap = (va_list)0)
    

      

    经验:

      在很多时候,我们希望在定义宏的时候也能够像printf函数一样可以使用边长参数,即宏的参数可以是任意个,这个功能可以由编译器的边长参数宏来实现。在GCC编译器下,边长参数宏可以使用“##”宏字符串链接操作实现,比如:

    #define printf(arg...) fprintf(stdout,##args)
    

      而在MSVC下,可以通过__VA_ARGS__这个编译器内置宏,比如:

    #define printf(...) fprintf(stdout,__VA_ARGS__)
    

      

  • 相关阅读:
    php 将富文本编辑后的内容取出
    阿里云Windows远程连接出现身份验证错误,要求的函数不正确”的报错。
    composer切换中国镜像
    php获取当月天数及当月第一天及最后一天、上月第一天及最后一天实现方法
    golang ioutil 包源码阅读
    ssh 远程登录 REMOTE HOST IDENTIFICATION HAS CHANGED 问题
    Golang -- fallthrough
    Golang 执行 go run main.go 显示 undefined
    Golang Playground 进度条示例
    关系型数据库和非关系型数据库(NOSQL)
  • 原文地址:https://www.cnblogs.com/Eric-scratch-paper/p/5027703.html
Copyright © 2011-2022 走看看