可变参数列表的4个宏解释:
首先,stdarg.h里定义了va_list:
typedef char * va_list;
说明va_list 是一个指针char * 类型 ,下面会用到。
//
(1)_INTSIZEOF(n)
定义如下:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
这个实际上是求n的对齐字节数,即为sizeof(int)的整数倍。
例如:sizeof(n)等于4 sizeof(int)等于4 那么
( (sizeof(n) + sizeof(int) - 1) 等于 7
(sizeof(int) - 1) ) 等于3 000000000000000000000000000000011
~(sizeof(int) - 1) ) 等于 -4 11111111 11111111 11111111 11111100
( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) =4 相当于把7的最后两个二进制位置为0(0111(7)置为0100(4))
//
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
这个宏把v的地址强制转换成va_list(char *)类型,然后加上v类型字节对齐的大小 赋值给ap 所以ap的值就是第一个固定参数后的第一个参数
例如:printf("%d",n); // "%d"是第一个参数,调用va_start就会把n的地址赋值给ap。
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //ap增加了,但是表达式的值却还是原来的值
这个宏很巧妙,巧妙在它的运算符上。 用va_arg(ap,t)赋值时得到的值就是ap所在地址 t类型的值,然后ap所保存的地址自动加t类型的长度。
相当于赋值后地址+1 。
#define va_end(ap) ( ap = (va_list)0 ) // (char * )0 避免出现野指针
这个宏是在最后使用的,将ap指针指向0地址,目的是避免ap这个指针指向未定义的地址。