【问题标题】:C++ Standard Args : multiple calls to va_startC++ 标准参数:多次调用 va_start
【发布时间】:2012-06-15 11:31:51
【问题描述】:

我注意到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 传递给另一个函数的正确方法是什么?

【问题讨论】:

    标签: c++ variadic-functions


    【解决方案1】:

    您可以将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++ 中,您应该使用可变参数模板来执行此操作,因为这些模板可以正确转发、完全类型安全,并且(如果您正确实现)不会冒缓冲区溢出的风险。

    希望这会有所帮助!

    【讨论】:

    • 正是我需要的,感谢您的解释。允许时接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多