函数中的不定参数

以前一直没去了解不定参数的使用,今天学习使用了一把:

int sum(int n, ...)
{
        va_list arglist;
        int result = 0;
        int i, value;

        va_start(arglist, n);

        printf("(");

        for (i = 0; i < n-1; i++)
        {
                value = va_arg(arglist, int);
                result += value;

                printf("%d+", value);
        }

        value = va_arg(arglist, int);
        result += value;

        printf("%d) = %d\n", value, result);

        va_end(arglist);

        return result;
}

这个是很简单直观的使用方法,像下面的调用:

        sum(1, 10);
        sum(2, 10, 20);
        sum(3, 10, 20, 30);
        sum(5, 1, 2, 3, 4, 5);

输出结果为:

(10) = 10
(10+20) = 30
(10+20+30) = 60
(1+2+3+4+5) = 15

使用不定参数需要用到 va_list 类型,和下面 3 个宏

  • va_start(ap, v)
  • va_arg(ap, t)
  • va_end(ap)

首先,需要定义一个 va_list 类型的变量,va_list 类型实质是 char * 类型:

typedef char * va_list;

宏 va_start(ap, v) 是给 va_list 变量赋初值,ap 是 va_list 类型变量,v 是不定参数列表的前一个参数

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

#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

va_start() 的作用是算出不定参数列表中的第 1 个参数的地址:

int sum(int n,  ...)
        ------   
          |                 
          +------------------> 根据不定参数列表前一个参数 n 的地址,算出不定参数列表中的第 1 个参数的地址

最简单的思维是 Address_Of(n) + Size_Of(n),其中 n 的地址很容易人 &n 取得,只是这个 Size_Of(n) 的获得需要费得心思:不可能直接用 sizeof 操作符来取。

不定参数中的数据类型可能是不一致的。或者有 int 类型,或者有 char 类型等等,它们的 sizeof 也就不一样。然而在 32 位代码下,processor 压入栈中的数据是对齐在 4 bytes 边界

即使是 char 类型的参数,push 入栈中也是 4 bytes 的(符号扩展到 4 bytes),因此不能简单地用 sizeof 取参数的字节数,应该要调整到下一个 4 bytes 边界上:

(sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)

这个式子就是做这项工作,假设 n 是 5 bytes 大小的结构体类型参数,它压入栈中的空间是 8 bytes,通过调整到 n 参数地址的下一个 4 bytes 边界上,这个结果就正确了。

再来看看 va_arg(ap, t) 这个宏,它的作用是获得 ap 参数的值

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

ap 是经过 va_start() 宏后,设置的不定参数列表的第 1 个参数的地址,t 是这个参数的类型。我们看到 va_arg() 宏的另一个作用是再次设置为不定参数列表下一个参数,计算方法同 va_start() 是一致的。 经过 va_arg() 宏后 ap 的值就是下一个参数的地址。

最后,使用完不定参数后,va_end() 宏的作用是清 va_list 类型变量为 NULL(它是指针类型)

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

不过,使用完后,即使不使用 va_end() 也完全没问题,它不像 malloc() 分配内存,必须使用 free() 释放内存,否则会发生内存泄漏。va_end() 将 va_list 类型变量清 0,不清 0 的话,我看不出有什么问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值