基本上C语言的可变参数原理在不同平台和不同编译器下基本类似(通过函数入栈,从右向左,从高位到低位地址),不过部分实现会有所不同;在使用中需要注意的是:
va_list 为char 类型指针,部分调用如vnsprintf、vsprintf(内部通过遍历获取va_arg各个参数值)等会修改其指针位置;在windows下通过一个副本va_list实现va_arg操作,而在linux下不会产生副本va_list,而是直接修改原va_list的指针对象;
在编写程序的时候,当调用了类似vnsprintf的函数后,若再次调用vnsprintf相关的其他需要用到va_list定义的类型指针对象时,将可能出现非预期的结果;在linux下便是如此,故当调用了类似vnsprintf的函数后应再次调用va_start,以重新调整va_list对象的指针位置(windows下无需再调用)。
示例代码段:
std::string formatstr(const char *format, ...) { std::vector<char> vec_str; va_list arg_list; va_start(arg_list, format); int len = vsnprintf(nullptr, 0, format, arg_list); if( len > 0 ) { vec_str.resize( len + 1); //va_start(arg_list, format); vsnprintf(&vec_str[0], len, format, arg_list); } va_end(arg_list); if(vec_str.size() > 0) { vec_str[len] = ' '; return &vec_str[0]; } return std::string(""); }
在windows的vs平台下以上代码可为预期结果,而在linux下输出却是随机的;若将注释段代码打开,则均可输出预期的结果;