为什么std::string不能作为可变参数‘...’前的最后命名参数?
va_start警告的原因解析
我实现了一个formatToStr()函数,接收const std::string&类型的格式参数,返回格式化后的字符串,代码如下:
#include <string> #include <cstdarg> std::string formatToStr(const std::string& format, ...) { char buff[1024]; va_list args; va_start(args, format.c_str()); vsnprintf(buff, sizeof(buff), format.c_str(), args); va_end(args); return std::string(buff); } int main() { printf("Testing: %s\n", formatToStr(std::string("test")).c_str()); return 0; }
编译此代码时出现如下警告:
$ g++ --version g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 ... $ g++ ./c.cpp ./c.cpp: In function ‘std::string formatToStr(const string&, ...)’: ./c.cpp:8:9: warning: second parameter of ‘va_start’ not last named argument [-Wvarargs] 8 | va_start(args, format.c_str()); | ^~~~~~~~
将format的类型修改为const char*后,警告消失,请问这是什么原因?
原因解释
C标准对va_start的使用有严格要求:它的第二个参数必须是函数最后一个命名参数(即紧跟在可变参数...之前的那个参数)。
在你的原始代码中,函数的最后一个命名参数是const std::string& format,但你调用va_start时传入的是format.c_str()——这是调用std::string成员函数返回的临时const char*值,并非函数的命名参数本身。编译器能识别到这个不符合规则的用法,因此抛出警告,而且这种写法还可能导致未定义行为,因为va_start无法通过临时值正确定位可变参数列表的起始位置。
当你把参数类型改为const char* format后,va_start(args, format)中的format就是函数的最后一个命名参数,完全符合va_start的标准使用规则,编译器自然不再发出警告。
内容的提问来源于stack exchange,提问作者hudac
相关产品推荐
相关产品推荐

