views:

1363

answers:

4

Okay, I'm aware that the standard dictates that a C++ implementation may choose in which order arguments of a function are evaluated, but are there any implementations that actually 'take advantage' of this in a scenario where it would actually affect the program?

Classic Example:

int i = 0;
foo(i++, i++);

Thanks.

Note: I'm not looking for someone to tell me that the order of evaluation can't be relied on, I'm well aware of that. I'm only interested in whether any compilers actually do evaluate out of a left-to-right order because my guess would be that if they did lots of poorly written code would break (rightly so, but they would still probably complain).

+7  A: 

It depends on the argument type, the called function's calling convention, the archtecture and the compiler. On an x86, the Pascal calling convention evaluates arguments left to right whereas in the C calling convention (__cdecl) it is right to left. Most programs which run on multiple platforms do take into account the calling conventions to skip surprises.

There is a nice article on Raymond Chen' blog if you are interested. You may also want to take a look at the Stack and Calling section of the GCC manual.

Edit: So long as we are splitting hairs: My answer treats this not as a language question but as a platform one. The language standard does not gurantee or prefer one over the other and leaves it as unspecified. Note the wording. It does not say this is undefined. Unspecified in this sense means something you cannot count on, non-portable behavior. I don't have the C spec/draft handy but it should be similar to that from my n2798 draft (C++)

Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. An instance of the abstract machine can thus have more than one possible execution sequence for a given program and a given input.

dirkgently
Ah of course. I should've thought of that. Thanks.
RaptorFactor
Just saw your edit. Thanks for the links! :)
RaptorFactor
Just to be clear, pascal/cdecl decides whether the arguments are *passed* left-to-right or right-to-left -- they can still be *evaluated* in any order. (Though due to register pressure it's likely that they'll be evaluated in the same order as they're passed.)
j_random_hacker
Wrong: C arguments are pushed onto the stack right to left. But the order they are evaluated is undefined.
Martin York
@Martin York: When did I say that the order is well-defined?
dirkgently
@Martin York: By C I had meant the C calling convention. Edited post.
dirkgently
@dirkgently: Your answer says that the calling convention determines evaluation order. As Martin York says, that's not true, it only defines the order in which they're pushed onto the stack.
jalf
@jalf: I didn't intend to. I'll clarify.
dirkgently
I've never met a compiler in the wild that evaluated the arguments in a different order than it pushed them on the stack. I've looked at a lot of generated code over quite a few years of embedded systems work. This is still a highly implementation-specific detail, of course.
RBerteig
@Martin York: The order is unspecified and not undefined.
dirkgently
RBerteig: I have met such a compiler.
jalf
The '98 C++ standard 5.2.2.8The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.
CsTamas
+1  A: 

Last time I saw differences was between VS2005 and GCC 3.x on an x86 hardware in 2007. So it's (was?) a very likely situation. So I never rely on evaluation order anymore. Maybe it's better now.

Robert Gould
Oh? That's very good to know. Thanks.Currently the only compilers I use are VC 08 and ICC 11. I should probably start testing my code in GCC too.
RaptorFactor
ICC goes great lengths to be as compatible with VS as possible. Good folks those Intel people :)
Robert Gould
VS doesn't guarantee an evaluation order either. They've changed how they evaluate function arguments before, and there's no reason why they wouldn't do so again. It is not something you should rely on.
jalf
+1  A: 

I expect that most modern compilers would attempt to interleave the instructions computing the arguments, given that they are required by the C++ standard to be independent and thus lack any interdependencies. Doing this should help to keep a deeply-pipelined CPU's execution units full and thereby increase throughput. (At least I would expect that a compiler that claims to be an optimising compiler would do so when optimisation flags are given.)

j_random_hacker
+3  A: 

Read this

It's not an exact copy of your question, but my answer (and a few others) cover your question as well.

There are very good optimization reasons why the compiler might not just choose right-to-left but also interleave them.

The standard doesn't even guarantee a sequential ordering. It only guarantees that when the function gets called, all arguments have been fully evaluated.

And yes, I have seen a few versions of GCC do exactly this. For your example, foo(0,0) would be called, and i would be 2 afterwards. (I can't give you the exact version number of the compiler. It was a while ago - but I wouldn't be surprised to see this behavior pop up again. It's an efficient way to schedule instructions)

jalf
common subexpression elimination is the main reason for optimization re-ordering. Remember that argument evaluation and parameter passing are allowed to be different, even though many compilers treat them identically.
plinth