C++变长参数

在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))

额,再凑点字数.....

 

posted @ 2022-08-10 18:59  待业大学生  阅读(401)  评论(0)    收藏  举报