2

我注意到va_start在两个函数中连续调用时存在一些问题。一个基本示例如下:

std::string format(std::string fmt, ...)
{
   char buf[2000];
   va_list aq;
   va_start(aq, fmt);
   vsprintf(buf, fmt.c_str(), aq);
   va_end(aq);
   return std::string(buf);
}
void error(std::string fmt, ...)
{
   va_list ap;
   va_start(ap, fmt);
   printf("%s", format(fmt, ap).c_str());
   va_end(ap); 
   exit(1);
}

int main()
{
   int x = 10;
   printf("%s", format("Test %d\n", x).c_str());
   error("Test %d\n", x);
}

生产

Test 10
Test -1078340156

似乎,在使用该error函数时,参数已损坏。

将 传递va_list给另一个函数的正确方法是什么?

4

1 回答 1

11

您将va_list明确地作为参数传递。将 a传递va_list给采用多个参数的函数不会“解包”这些参数。相反,它只是用两个参数调用函数,第二个参数是 a va_list。您从函数中获取垃圾的原因是它试图将其解释va_list为 的参数之一printf,从而导致未定义的行为。

这就是为什么有类似函数的原因vsprintf- 这样函数喜欢printfsprintf可以在内部调用辅助函数来进行格式化,给定va_list参数。

例如:

std::string vformat(std::string fmt, va_list args) {
   char buf[2000];
   vsprintf(buf, fmt.c_str(), args);
   return std::string(buf);
}

void error(std::string fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   printf("%s", vformat(fmt, ap).c_str());
   va_end(ap); 
   exit(1);
}

尽管如此,在 C++ 中,您应该使用可变参数模板来执行此操作,因为它们可以正确转发,完全类型安全,并且(如果您正确实现它)不会冒缓冲区溢出的风险。

希望这可以帮助!

于 2012-06-15T02:45:13.983 回答