• C语言函数可变长度参数剖析


    C语言中的很多函数的入参被定义为可变参数,最典型的

    int printf (const char * fmt, ...)

    要对其中的可变参数进行处理,就要用到va_list类型和 VA_START, VA_END, VA_ARG 宏 ,需要包含<stdarg.h>头文件

    利用va族函数对不定参数进行解析的过程所示如下:

     1 int my_printf(const char * fmt, ...)
     2 {
     3     va_list struAp;
     4     va_start(struAp, fmt);
     5 
     6     for (; *fmt; ++fmt)
     7     {
     8         if(*fmt != '%')
     9         {
    10             PUTC(*fmt); 
    11             continue;
    12         }
    13         
    14         fmt++;
    15         
    16         switch (*fmt)
    17         {
    18             case 'd':
    19             {
    20                 int i = va_arg(struAp,int);
    21                 PUTC(i);
    22             }
    23             break;
    24 
    25             default:
    26                 break;
    27         }
    28     }
    29     
    30     va_end(struAp);
    31 }

    要了解不定参数的处理方式,就要搞清楚va族函数的实现

    #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

    /* 实质就是一个char型的指针 */

    typedef char * va_list;

    /* 将指针偏移一个v的长度,指向后面的地址 */

    #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

    /* 根据参数类型,取出后面的数据,强制类型转换 */

    #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

    /* 将指针置为NULL */

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

    通过解析fmt字符串,得到后面的参数类型和个数,根据参数类型再加上偏移量就可以找到栈中的不定参数了

     函数调用和传参的过程所示如下:

    将函数参数与函数调用后下一条指令的地址都压入栈中,然后跳到函数的入口地址。

    例如

    void func(int param1, double param2,int param3){ }
    
    int main()
    { 
        func(3, 1.2, 4); 
        printf("Over
    "); //设指令地址为0x1234
        return 0;
    }

    执行f(3, 1.2, 4)的函数调用,进入func函数时的堆栈如下:

     
     这样,通过param1的地址就可以计算出param2与param3的地址:
     
    使用不定参函数的注意事项
     
    • 在C语言中,调用一个可变参数函数时,调用者会对每个参数执行“默认实际参数提升(default argument promotions)”

         ——float类型的实际参数将提升到double
      ——char类型的实际参数将提升到int
      ——short类型的实际参数将提升到int

    • 在没有函数原型的情况下,char与short类型都将被转换为int类型,float类型将被转换为double类型。

                 ——《C语言程序设计》第2版  2.7 类型转换 p36

    • 这样写肯定是不对的:

        c = va_arg(ap,char);

      因为我们无法传递一个char类型参数,如果传递了,它将会被自动转化为int类型。上面的式子应该写成:
      c = va_arg(ap,int);

                    ——《C陷阱与缺陷》p164
  • 相关阅读:
    天融信防火墙抓包
    windows2019jihuo
    CentOS多路径软件配置(光纤连接存储)
    listener.ora,tnsnames.ora中一个空格的威力
    excel 金额自动转中文大写
    js的点滴
    写ppt的助手
    珠峰-6-koa-express
    珠峰-6-http和http-server原理
    珠峰-6-node
  • 原文地址:https://www.cnblogs.com/li-hao/p/3401942.html
Copyright © 2020-2023  润新知