#ifdef _M_CEE_PURE
typedef System::ArgIterator va_list;
#else
typedef char * va_list;
#endif /* _M_CEE_PURE */
我们使用 typedef char* va_list;//va_list是一个指向char的函数指针
#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
_ADDRESSOF(v)的作用是取得v变量的地址。
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
以int所占的字节为标准进行对其操作。
如果int占四字节,则以四字节对齐为标准读取数据。
在stdarg.h中有下面三个宏的定义
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
红色标注的宏是用户直接使用的宏,下面我们来看一下他们各自的实现,即绿色标注的部分。
在vadefs.h中有上述绿色标注部分的实现。
#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 )
解析
1. #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
(va_list)_ADDRESSOF(v)得到v的地址
INTSIZEOF(v) 字节对齐后v的大小
最后ap指向v的下一个对象的指针,即所以ap 就指向v后面的参数的起始地址。
2.
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )分为以下几个step解析:
(1) ap += _INTSIZEOF(t) 指向类型为t的下一个参数的地址。
(2) (ap += _INTSIZEOF(t))- _INTSIZEOF(t) 指向当前类型为t的参数的指针
(3)(t*)((ap += _INTSIZEOF(t))- _INTSIZEOF(t))将当前指针转换成t类型的指针
(4)( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取得当前指针的值。
3.#define _crt_va_end(ap) ( ap = (va_list)0 )
将va_list置成无效指针。
以上是printf()变参的实现过程。