views:

198

answers:

3

I'm trying to use va_arg to make a generic factory function in my GUI library. When passing va_arg twice in the same function they pass on the same value instead of two different:

GUIObject* factory(enumGUIType type, GUIObject* parent, ...){
   va_list vl;
   va_start(vl, parent);
   ...
   label->SetPosition(va_arg(vl, int), va_arg(vl, int));
   va_end(vl);
   return finalObjectPointer;
}

factory(LABEL, theParent, 100,200); // Results in position 200:200

What causes this unexpected behavior?

+5  A: 

The compiler is not guaranteed to evaluate arguments in order. Add some additional local variables and do the two assignments in sequence.

See this other stack overflow posting.

int v1 = va_arg(vl, int);
int v2 = va_arg(vl, int);

label->SetPosition(v1, v2);

To get what you are observing: the exact same value twice -- probably requires a compiler bug piled on top of the undefined order of evaluation situation, or some entertaining aspect of the particular macro expansion of va_arg in your environment.

bmargulies
+2  A: 

There are no sequence points in between the evaluations of different arguments, so modifying the same value (vl or something it refers to) twice while evaluating the arguments leads to unspecified behaviour.

va_arg changes the internal state of vl to register which arguments are already handled, and when doing this twice during argument evaluation it is unspecified what happens. Your compiler and the optimizations it uses seem to result in two identical parameters being passed.

sth
+6  A: 

va_arg is a macro. What's hiding behind that macro is implementation defined, which means that it is quite possible that operations performed in place of va_arg have side effects. For this reason, it is not a good idea to use va_arg more than once between two adjacent sequence points. This is potentially undefined behavior, meaning that anything can happen. Looks like this is exactly what happens in your case, which results in this "weird" behavior when you get two identical values from va_arg.

Even if there's no undefined behavior in some implementation, the order of argument evaluation in a function call is unspecified, meaning that using any "sequential readers" in the way you use them is not guaranteed to work as intended (whatever it is you intended).

AndreyT