可变参数列表剖析
附上一段代码
#include <stdarg.h>
int aver(int n,...)
{
int i = 0;
int sum = 0;
va_list arg;
va_start(arg, n);
for(i = 0; i<n; i++)
{
sum += va_arg(arg,int);
}
va_end(arg);
return sum/n;
}
#
typedef char * va_list;
我们发现va_list实际上是char * ,因此上一段代码 arg被定义成一个字符串指针;
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
_INTSIZEOF(n) 是一个宏,是向上求整,大小为4的倍数,如图所示:
va_start实际上也是一个宏,上段代码的va_start(arg, n);可根据替换为
(arg = (char *)&n + 4)
#define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
va_arg(ap,t) 也是一个宏,上段代码va_arg(arg,int)替换后为((int )((arg += 4) - 4))。我们发现,arg已经指向了下一个整形值,而整个表达式还指向原表达式,类似于自加的效果;
#define va_end(ap) ( ap = (va_list)0 )
上段代码:va_end(arg) 是将 arg指向0;
因此上段代码可改为如下:
int aver(int n,...)
{
int i = 0;
int sum = 0;
char *arg;
va_start(arg, n);
arg = (char *)&n + 4;
for(i = 0; i<n; i++)
{
sum += (*(int *)((arg += 4) - 4));
}
arg = (char *)0;
return sum/n;
}
注释了的代码:
#include <stdarg.h>
int aver(int n,...)
{
int i = 0;
int sum = 0;
va_list arg; //char *arg;
va_start(arg, n);
//(arg = (char *)&n + _INTSIZEOF(n));//_INTSIZEOF是向上取整;
//(arg = (char *)&n + 4);//指向[参数总个数]后的第一个参数;
for(i = 0; i<n; i++)
//va_start:初始化arg,让其指向未知参数后的第一个参数;
{
sum += va_arg(arg,int);//int 不能写错
//sum += (*(int *)((arg += 4) - 4));
}
va_end(arg);//arg = (char *)0;
return sum/n;
}