C++变长参数
void va_start( std::va_list ap, parm_n ); T va_arg( std::va_list ap, T ); void va_copy( std::va_list dest, std::va_list src ); void va_end( va_list ap ); typedef /* unspecified */ va_list; //以上描述出自 cppreference.com
//以上宏被定义于头文件<cstdarg>
(注:本人使用的编译器是MSCV。)
va_list
#ifdef _M_CEE_PURE typedef System::ArgIterator va_list; #else typedef char* va_list; #endif
在我的编译器中使用的是第二个定义,即char*。换成其他指针应该也没有区别,至于为什么是字符指针,应该是考虑到print这类函数是主要的使用对象。
第一个定义中的ArgIterator在编译器里面没有定义,在微软里的描述是:
Represents a variable-length argument list; that is, the parameters of a function that takes a variable number of arguments.
public ref struct ArgIterator
好像是C#的类型,不知道为什么会出现在这里。
va_start
//<cstdarg> #define va_start __crt_va_start //<vadefs> define __crt_va_start(ap, x) ((void)(__vcrt_assert_va_start_is_not_reference<decltype(x)>(), __crt_va_start_a(ap, x))) //<vadefs> #define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))
其中__vcrt_assert_va_start_is_not_reference是一个静态断言的宏,以下是断言的输出:
"va_start argument must not have reference type and must not be parenthesized"
翻译:“va_start参数不得具有引用类型,并且不得用括号括起来”
总之,跳过断言的部分va_start其实是在调用这个vadefs文件中的__crt_va_start_a,其中涉及的两个宏如下:
#define _ADDRESSOF(v) (&const_cast<char&>(reinterpret_cast<const volatile char&>(v))) #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
简单说一下这两个宏的作用
_ADDRESSOF(v) :获取变量v(纯净版)的地址。
_INTSIZEOF(n) :sizeof(int)的倍数中,大于sizeof(n)的最小数。
最后回到一开始的宏va_start,按照描述,最后得到的ap就是变长参数列表的首地址。(经过测试,普通函数与变参函数还包括内联函数中相邻参数的地址也都是4的倍数。)
va_arg
//<stdarg> #define va_arg __crt_va_arg //<vadefs> #define __crt_va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
其中_INTSIZEOF与上文中提到的一致。
总结一下,va_arg的作用是从列表中获取一个值,并将ap移动到下一个值的首地址。
va_copy
//<stdarg> #define va_copy(destination, source) ((destination) = (source))
凑点字数......
va_end
//<stdarg> #define va_end __crt_va_end //<vadefs> #define __crt_va_end(ap) ((void)(ap = (va_list)0))
额,再凑点字数.....

浙公网安备 33010602011771号