C语言中的变长参数

我们在C语言编程中会遇到一些参数个数可变的函数,例如printf() ,这个函数,它的定义是这样的: 

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

然而,变长参数的函数到底怎么实现呢?

要实现这样一个变长参数的函数需要用到数据结构va_list,和宏va_start,va_arg,va_end,这些都是定义在stdarg.h中的宏。

va_list是定义了一个保存函数参数的数据结构。

va_start宏用来初始化va_list变量,其第一个参数为va_list对象,第二个参数为可变参数的前一个参数,是一个固定参数

在初始化完成va_list变量后,即可使用va_arg宏

va_arg宏用来得到后边的可变参数,其第一个参数为va_list对象,第二个参数为返回参数的类型

va_end宏用来结束变量的获取,将其指针持有变量置0


下面是是va_list的具体实现实现(vc 2003):

#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

可以看到va_list实际上是一个机器类型相关的宏,除了alpha机器以外,其他机器类型都被定义为一个char类型的指针变量,之所以定义为char *是因为可以用该变量逐地址也就是逐字节对参数进行遍历。

宏的实现如下,内容比较容易懂,就不介绍了,如下:

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

#define va_start(ap,v)   ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define va_arg(ap,t)     ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)       ( ap = (va_list)0 )

#ifdef   __cplusplus
#define _ADDRESSOF(v)    ( &reinterpret_cast<const char &>(v) )
#else
#define _ADDRESSOF(v)    ( &(v) )
#endif

参考代码如下:

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

void test(char src[], ...);

int main()
{
    char str[] = "content";
    test("this is %d %s %c", 123, str, 'p');
    return 0;
}

void test(char src[], ...)
{
    int num=1;

    va_list args;

    va_start(args, src);

    int i = 1;
    int len = strlen(src);
    while(i<len)
    {
        if(src[i-1] == '%')
        {
            switch(src[i])
            {
                case 'd':
                {
                    int p = va_arg(args, int);
                    printf("%d args :  %d\n", num++, p);
                    break;
                }
                case 'c':
                {
                    //处理字符串的时候,va_arg宏会将参数自动提升为整型
                    int ch = va_arg(args, int);
                    printf("%d args : %c\n", num++, (char)ch);
                    break;
                }
                case 's':
                {
                    char * pStr = va_arg(args, char *);
                    printf("%d args : %s\n", num++, pStr);
                    break;
                }
            }
        }
        i++;
    }
    va_end(args);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值