Archived

This topic is now archived and is closed to further replies.

Barguast

va_list problem

Recommended Posts

Can someone explain to be why...
void testfunc (const int a, ...)
{
	va_list Params;
	va_start (Params, a);
		cout << va_arg (Params, int);
	va_end (Params);
}

void main()
{
	testfunc (5, 6);
}
  
This correctly outputs '6', whereas this:
void testfunc (const int &a, ...)
{
	va_list Params;
	va_start (Params, a);
		cout << va_arg (Params, int);
	va_end (Params);
}

void main()
{
	testfunc (5, 6);
}
  
Outputs '1245120'... (I don't think there is any signficance to this value) This different is that in one 'a' is passed by value, and in the other it's passed by reference. Lets say I NEED to pass this by reference (because in my real program it's a std::string), how can I fix this so that it works? [edited by - Barguast on April 23, 2004 10:06:37 AM]

Share this post


Link to post
Share on other sites
I don''t know exactly why it''s behaving that way, but you''re certainly doing something you shouldn''t - if you pass something by reference, you shouldn''t pass a literal constant, you should pass a variable. For example:

void main()
{
int a = 5;

testfunc(a, 6);
}


Try that.

Share this post


Link to post
Share on other sites
Aprosenf - You can pass literal by const reference. The compiler will generate a temporary variable to hold it.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Well im not 100% sure how va_list is implemented, but i would image that it uses the address of the a element as the starting point of an array of parameters, and since you are passing it by referece, the address of the variable will not be the address of the start of the parameter list.

Share this post


Link to post
Share on other sites
Barguast - In the va_start macro, the a parameter is intended to let the compiler know where the argument list starts. It all has to do with the C calling convention: the arguments are all adjacent in memory. Now, when you pass by reference, the a you give to the macro is not in the right place, but instead points to the original location of the variable you passed (here, the temporary that the compiler generated to hold the literal 5). The memory location that would have held a in the argument list will instead hold the address of a (as if it were a pointer), but the compiler automatically adds a dereference when it is used.

So basically, the code you wrote is equivalent to:

void testfunc (const int* a, ...)
{
va_list Params;
va_start (Params, *a);
cout << va_arg (Params, int);
va_end (Params);
}

void main()
{
int x = 5;
testfunc (&x, 6);
}


From *a there is no way you can find the remaining parameters.

Remember that varargs are a C library utility. Not a C++ one.
Consequences:
a) Don't pass by reference when using varargs. If really necessary, take the address of the variable and pass by pointer.
b) You cannot access (non-POD) object types through the va_arg macro.

[edited by - Fruny on April 23, 2004 10:51:21 AM]

Share this post


Link to post
Share on other sites