C ++标准参数:对va_start的多次调用

时间:2012-06-15 02:42:24

标签: c++ variadic-functions

在两个函数中连续调用时,我注意到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传递给另一个函数的正确方法是什么?

1 个答案:

答案 0 :(得分:11)

您可以明确地将va_list作为参数传递。将va_list传递给采用多个参数的函数不会“解包”这些参数。相反,它只是用两个参数调用函数,第二个参数是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 ++中你应该使用可变参数模板来执行此操作,因为它们可以正确转发,完全类型安全,并且(如果正确实现)不会冒缓冲区溢出的风险。

希望这有帮助!