一、源码剖析
在介绍可变参数列表之前,先补充两个宏
1._ADDRESSOF(v)
源码 :
作用:对变量v取地址
2._INTSIZEOF(n)
源码:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
作用:将n的长度化为int长度的整数倍
原理:上式等于(sizeof(n)+3)&~(3)
其中~(3)=11111111 11111111 11111111 11111100
任何数&~(3)之后的二进制最后两位一定为00
则:如果4*i< num< 4 * (i+1) (i>=0,i∈Z) ,那么 num&~3=4 *(i+1);如果num等于4的整数倍,num&~3=num。
又因为(sizeof(n)+3)>=4;所以将保证把n的长度提升到4的倍数,即化为int长度的整数倍
读懂上面两个宏之后可以继续了解可变参数列表,可变参数列表包括:
1.va_list
源码:
typedef char * va_list;
也就是说va_list是个char类型指针
2.va_arg
源码:
#define va_arg _crt_va_arg
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
意思:将指针ap指向当前位置移动_INTSIZEOF(t)个字节后的位置,然后取现在的ap所在位置的前 _INTSIZEOF(t)个字节的位置(ap移动前的原位置),并将其强制转换成t类型,然后对其解引用,取出这个地址的内容。
作用:将ap移位_INTSIZEOF(t)个字节后,再取出ap移位前的位置对应的数据
如图:
3.va_copy(暂不做解释,后期补充)
源码:
void _CRTIMP __cdecl _vacopy(_Out_ va_list *, _In_ va_list);
#define va_copy(apd, aps) _vacopy(&(apd), aps)
4.va_start
源码:
#define va_start _crt_va_start
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
作用:对v取地址,并强制转换成va_list即char *类型,再将其移动 _INTSIZEOF(v)个字节后的地址赋给ap
5.va_end
源码:
#define va_end _crt_va_end
#define _crt_va_end(ap) ( ap = (va_list)0 )
作用:将0强制转换成va_list即char *类型,赋给ap,即将ap置空
二、实例解析
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
int average(int n,...)//n代表参数个数
{
int i = ;
int sum = ;
va_list arg;
va_start(arg, n);
for (i = ; i < n;i++)
{
sum += va_arg(arg,int);
}
va_end(arg);
return sum/n;
}
int main()
{
int ret = average(,,,);
printf("ret= %d\n",ret);
system("pause");
return ;
}
将上面代码转换成我们能看得懂的代码,如下:
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
int average(int n, ...)//n代表参数个数
{
int i = ;
int sum = ;
//va_list arg;
char *arg;
//va_start(arg, n);
//arg = (char *)_ADDRESSOF(n) + _INTSIZEOF(n);
//arg = (char *)&n + ((sizeof(n)+3) & ~3);
arg = (char *)&n +;
for (i = ; i < n; i++)
{
//sum += va_arg(arg, int);
//sum += *(int *)((arg += _INTSIZEOF(int)) - _INTSIZEOF(int));
//sum += *(int *)(arg+=((sizeof(int)+3) & ~3) - ((sizeof(int)+3) & ~3));
sum += *(int *)(arg+= - );
}
//va_end(arg);
arg = (char *);
return sum / n;
}
int main()
{
int ret = average(,,,);
printf("ret= %d\n",ret);
system("pause");
return ;
}
代码的功能如下图所示: