zoukankan      html  css  js  c++  java
  • 【C/C++开发】C语言实现函数可变参数

           函数原型: int printf(const char *format[,argument]...)
           返 回 值: 成功则返回实际输出的字符数,失败返回-1.
     函数说明:
           在printf()函数中,format后面的参数个数不确定,且类型也不确定,这些参数都存放在栈内.调用printf()函数时,根据format里的格式("%d %f...")依次将栈里参数取出.而取出动作要用到va_arg、va_end、va_start这三个宏定义,再加上va_list.
         (1)va_list事实上是一char *类型,即:
                typedef char* va_list;
         (2)三个宏定义:
                #define _INTSIZEOF(n)    ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) 
                #define va_start(ap,v)     ( ap = (va_list)&v + _INTSIZEOF(v) ) 
                #define va_arg(ap,type)  ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 
                #define va_end(ap)          ( ap = (va_list)0 ) 
       【attentionC语言中可变参数的原理---printf()函数 
                int printf(const char* format,...);   
          使用过C语言的人所再熟悉不过的printf函数原型,它的参数中就有固定参数format和可变参数(用”…”表示).而程序员又可以用各种方式来调用printf,如: 
                printf("%d ",value);   
                printf("%s ",str);   

                printf("the number is %d,string is:%s ",value,str); 
           可以看出,该函数的参数格式不固定,参数类型不固定.在C语言中使用宏来处理这些可变参数.这些宏看起来很复杂,其实原理挺简单,即根据参数入栈的特点从最靠近第一个可变参数的固定参数开始,依次获取每个可变参数的地址.
     (1)宏va_start
          通过该宏定义可以获取到可变参数表的首地址,并将该地址赋给指针ap.
     (2)宏va_arg
          通过该宏定义可以获取当前ap所指向的可变参数,并将指针ap指向下一个可变参数.注意,该宏的第二个参数为类型.
     (3)宏va_end
          通过该宏定义可以结束可变参数的获取.


          程序员通过这三个宏定义就可以实现对可变参数的处理.例如:


       #include <stdio.h>  
      
    typedef char* va_list;   
       #define _INTSIZEOF(n)    ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )   
       #define va_start(ap,v)   ( ap = (va_list)&v + _INTSIZEOF(v) )   
       #define va_arg(ap,type)  ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )   
       #define va_end(ap)       ( ap = (va_list)0 )   
      
    int cal_val(int c, ...)   
    {   
        int sum = c;   
        va_list ap;              //声明指向char型的指针  
        va_start(ap,c);          //获取可变参数列表的首地址,并赋给指针ap  
      
        c = va_arg(ap,int);      //从可变参数列表中获取到第一个参数(返回值即为参数)  
        while(0 != c)   
        {   
            sum += c;   
            c = va_arg(ap,int);  //循环的从可变参数列表中获取到参数(返回值即为参数)  
        }  
        va_end(ap);              //结束从可变参数列表中获取参数  
        return sum;   
    }    
       
    int main(int argc, char* argv[])   
    {   
        int value1;  
          
        value1 = cal_val(1,2,3,4,5,6,7,8,9,0);   
        printf("value1=%d/n",value1);  
        value2 = cal_val(6,7,8,9,0);   
        printf("value2=%d/n",value2);  
          
        return 0;   
    }   


  • 相关阅读:
    bzoj4165 矩阵 堆维护多路归并
    bzoj2802 [Poi2012]Warehouse Store 贪心+堆
    bzoj1367 [Baltic2004]sequence 左偏树+贪心
    bzoj3011 [Usaco2012 Dec]Running Away From the Barn 左偏树
    uoj207 共价大爷游长沙 子树信息 LCT + 随机化 + 路径覆盖
    bzoj4764 弹飞大爷 LCT
    bzoj4817 & loj2001 [Sdoi2017]树点涂色 LCT + 线段树
    bzoj5020 & loj2289 [THUWC 2017]在美妙的数学王国中畅游 LCT + 泰勒展开
    bzoj4998 星球联盟 LCT + 并查集
    bzoj3091 城市旅行 LCT + 区间合并
  • 原文地址:https://www.cnblogs.com/huty/p/8517288.html
Copyright © 2011-2022 走看看