Reputation: 681
I'm getting an access violation error (using Microsoft Visual C++ 2005) when passing a va_list parameter from one member function to another by value. If I pass it by reference everything works as expected but va_list isn't supposed to be passed by reference, is it?
class A
{
public:
char * getformatted( char const * a_format, ... )
{
va_list argp;
va_start( argp, a_format );
char * result = getformatted( a_format, argp );
va_end( argp );
return result;
}
char * getformatted( char const * a_format, va_list /*&*/ a_args )
{
static char buffer[ 256 ];
int length = vsprintf( buffer, a_format, a_args ); // Access violation.
return buffer;
}
};
int main( int argc, char * argv[] )
{
char * str = A().getformatted( "foo%s", "bar" );
return 0;
}
Upvotes: 1
Views: 1033
Reputation: 54634
In <stdarg.h>
:
typedef char * va_list
so A().getformatted( "foo%s", "bar" )
is calling A::getformatted( char const * a_format, va_list /*&*/ a_args)
due to a string literal decaying to char *
due to C compatibility.
Upvotes: 2
Reputation: 48307
If you step through execution, are both functions being called in the expected order?
Both the functions shown have similar signatures, so the first check is to make sure the call is occurring properly. This is particularly important since va_list
is typically a typedef to char *
, so getformatted("foo%s", "bar")
could very well be called without getformatted(const char *, ...)
being called first.
If that is the case, and vsprintf
uses va_next
at any point, the behavior will be undefined. Some compilers handle the va_
functions as simple macros, while others have significant functions.
Typically to solve this, the function with va_list
will be prefixed with a v
(vsprintf
et al) to remove any potential ambiguity.
In the best case, since you're using C++, a std::stringstream
or boost::format
are generally preferable. Both will give you type safety and prevent most situations like this, while the latter retains most of printf
's syntax.
Upvotes: 1