Loïc Février
Loïc Février

Reputation: 7750

C++ Standard Args : multiple calls to va_start

I've noticed some problem with va_start when call successively in two functions. A basic example would be the following one :

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

produces

Test 10
Test -1078340156

It seems that, when using the error function the arguments are corrupted.

What would be the right way to pass the va_list to another function ?

Upvotes: 2

Views: 4549

Answers (1)

templatetypedef
templatetypedef

Reputation: 372814

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!

Upvotes: 11

Related Questions