va_list problem

Started by
5 comments, last by Barguast 19 years, 12 months ago
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]
Using Visual C++ 7.0
Advertisement
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.
No, that does exactly the same!
Using Visual C++ 7.0
Aprosenf - You can pass literal by const reference. The compiler will generate a temporary variable to hold it.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
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.
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]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
That''s a shame... Still, thanks for clearing it up
Using Visual C++ 7.0

This topic is closed to new replies.

Advertisement