va_list 可变参数变量

 

VA_LIST 是在C语言中解决变参问题的一组宏

他有这么几个成员:

1) va_list型变量:

#ifdef  _M_ALPHA
typedef struct {
        char *a0;       /* pointer to first homed integer argument */
        int offset;     /* byte offset of next parameter */
} va_list;
#else
typedef char *  va_list;
#endif

2)_INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍:

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

3)VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):

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

4)VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):

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

5)VA_END宏,清空va_list可变参数列表:

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

VA_LIST的用法:     
       (1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
       (2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;
       (3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
       (4)最后用VA_END宏结束可变参数的获取。
使用VA_LIST应该注意的问题:
   (1)可变参数的类型和个数完全由程序代码控制,它并不能智能地识别不同参数的个数和类型;
   (2)如果我们不需要一一详解每个参数,只需要将可变列表拷贝至某个缓冲,可用vsprintf函数;
   (3)因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码;

小结:可变参数的函数原理其实很简单,而VA系列是以宏定义来定义的,实现跟堆栈相关。我们写一个可变参数的C函数时,有利也有弊,所 以在不必要的场合,我们无需用到可变参数,如果在C++里,我们应该利用C++多态性来实现可变参数的功能,尽量避免用C语言的方式来实现。

 

 

实例:  

大家比较熟悉的printf函数,前面是输出的字符串的格式,后面跟着的是可变的输入参数.

这种可变的参数如何做出来的呢?

va_list和va_arg.

va_list获取的是指定的参数列表,va_arg是把当前位置的输入参数转换为指定的类型,

由此可以得到一个实现printf的思路...

///  
void print(char *szBuf, char *fmtStr, ...)  
{  
    char *fmt;  
    char *cb;  
    char *szTmp;  
    char c;  
    int nTmp;  
    unsigned int uiTmp;  
      
    cb = szBuf;  
    fmt = fmtStr;  
      
    va_list ap;  
    va_start(ap, fmtStr);  
    while(*fmt)  
    {  
        if (*fmt != '%')  
        {  
            *cb = *fmt;  
            cb++;  
            fmt++;  
            continue;  
        }  
          
        fmt++;  
          
        switch(*fmt)  
        {  
            case 'd':  
                nTmp = va_arg(ap, int);  
                _itoa(nTmp, cb, 10);  
                while(*++cb) ;  
                break;  
            case 'x':  
                uiTmp = va_arg(ap, unsigned int);  
                _itoa(uiTmp, cb, 16);  
                while(*++cb) ;  
                break;  
            case 's':  
                szTmp = va_arg(ap, char *);  
                while(*szTmp)  
                {  
                    *cb++ = *szTmp;  
                    szTmp++;  
                }  
                break;  
            case 'c':  
                c = va_arg(ap, char);  
                *cb++ = c;  
                break;  
            default:  
                *cb++ = '%';  
        }  
        fmt++;  
    }  
    *cb = 0;  
    va_end(ap);  

///
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值