2

va_start2つの関数で連続して呼び出すときに問題が発生することに気づきました。基本的な例は次のとおりです。

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

You would pass the va_list explicitly as an argument. Passing a va_list to a function taking multiple parameters does not "unpack" those parameters. Instead, it just calls the function with two parameters, the second of which is a va_list. The reason you're getting garbage out of the function is that it's trying to interpret that va_list as one of the arguments to printf, causing undefined behavior.

This is why there are functions like vsprintf - it's so that functions like printf or sprintf can internally call a helper function to do the formatting, given the va_list of arguments.

For example:

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);
}

Though, that said, in C++ you should be using variadic templates to do this, because those can be forwarded correctly, are fully type-safe, and (if you implement it correctly) don't risk buffer overruns.

Hope this helps!

于 2012-06-15T02:45:13.983 に答える