views:

224

answers:

2

I have a class non-static member function, and it has variable arguments, I'm compiling on Visual Studio 2005, with the 64-bit runtime, on 64-bit Windows.

void Class::Foo(void* ptr,...)
{
    va_list args;
    va_start(args,ptr);
    float f=va_arg(args,float);
    va_end(args)
}

I'm expecting a float, I pass a float to the function. But when I debug - I don't get the float I've passed. In fact - it's being received by the function as a 64-bit double! I have to do this:

double d=va_arg(args,double);
float f=(float)d;

Now I know Win64 likes to pass parameters in registers, and casts floats when it does this, shouldn't a va_list always be on the stack?

According to most references, I should have just a clean stack full of the passed parameters.

My question is: is this correct behaviour, or a bug? And if it's a bug, is it my bug, or Microsoft's?

I have the defines WIN64 and _M_AMD64, and WIN32 is undefined.

+1  A: 

I don't have the C++ standard here, but it follows the C standard in this matter. C99, 6.5.2.2p7 says

If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

So for your float argument, "default argument promotions" are performed. These are defined in p6 as

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. [...]

So all floats are converted to double when being passed to an ellipse. VS apparently conforms in this respect, and the bug is in your code, which shouldn't use float in va_arg.

Martin v. Löwis
I think this is correct. Although there's nothing in the C++ standard about "default argument promotions", in the absence of that I believe that the C standard applies. As I understand it, the text you quoted says that because an argument passed to a variable-argument function is not prototyped (because you can't prototype the types when they're variable), they are always promoted to the biggest relevant type - int or double. Odd behaviour I think - but apparently these are the rules.
Roderick
+1  A: 

Looks like it is a VC++ x64 bug.

FIX: The va_arg function returns an incorrect value in a Visual C++ 2005 application

jcopenha