C语言的可变参数函数看起来是不很酷,必须printf之类的,初学时,一头雾水,不禁感觉到宇宙的浩瀚和自己的渺小啊,但是等你知道其中原理之后,也就淡定了:)
下面首先看一个程序:
#include "stdarg.h"
#include <iostream>
double AddManyNum(int n, ...)
{
va_listargList;
va_start(argList,n);
doublesum = 0.0;
for(inti = 0; i < n; ++i)
{
doublet = va_arg(argList, double);
sum+= t;
}
va_end(argList);
return sum;
}
int main()
{
doublers = AddManyNum(5, 1.0, 2.0, 3.0, 4.0, 5.0);
printf("%lf\n",rs);
}
这就是一个典型的可变参数函数
Va_start
Va_arg
Va_end
跟进之后发现其定义如下:
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
再跟进他们的宏定义:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) &~(sizeof(int) - 1) )
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v))
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) -_INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
分别解释一下:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) &~(sizeof(int) - 1) )
这个主要是字节对齐,这里是使用int占用字节数对齐,所以32位平台的话应该是4字节
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v))
这个函数主要是将ap的指针偏移到第一个参数位置,在上面的函数中就是n后面的底一个数
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) -_INTSIZEOF(t)) )
这个就是根据t参数的大小,取下参数t的值;
上面函数的参数我都默认设置成double,所以处理起来简单了不少,像printf这种支持变参数类型的函数的话,其内部会先对格式字符串进行处理,然后得出每个参数的类型,再去取相应的参数值。
#define _crt_va_end(ap) ( ap = (va_list)0 )
将参数列表指针置零
看到这里以前不会的同学是不是淡定了很多呢,呵呵