Compilers and argument order of evaluation in C++

22,371

Solution 1

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.

Solution 2

I found answer in c++ standards.

Paragraph 5.2.2.8:

The 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.

In other words, It depends on compiler only.

Solution 3

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)

Solution 4

All arguments are evaluated. Order not defined (as per standard). But all implementations of C/C++ (that I know of) evaluate function arguments from right to left. EDIT: CLang is an exception (see comment below).

I believe that the right-to-left evaluation order has been very very old (since the first C compilers). Certainly way before C++ was invented, and most implementations of C++ would be keeping the same evaluation order because early C++ implementations simply translated into C.

There are some technical reasons for evaluating function arguments right-to-left. In stack architectures, arguments are typically pushed onto the stack. In C/C++, you can call a function with more arguments than actually specified -- the extra arguments are simiply ignored. If arguments are evaluated left-to-right, and pushed left-to-right, then the stack slot right under the stack pointer will hold the last argument, and there is no way for the function to get at the offset of any particular argument (because the actual number of arguments pushed depends on the caller).

In a right-to-left push order, the stack slot right under the stack pointer will always hold the first argument, and the next slot holds the second argument etc. Argument offsets will always be deterministic for the function (which may be written and compiled elsewhere into a library, separately from where it is called).

Now, right-to-left push order does not mandate right-to-left evaluation order, but in early compilers, memory is scarce. In right-to-left evaluation order, the same stack can be used in-place (essentially, after evaluating the argument -- which may be an expression or a funciton call! -- the return value is already at the right position on the stack). In left-to-right evaluation, the argument values must be stored separately and the pushed back to the stack in reverse order.

Solution 5

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.)

Share:
22,371
RaptorFactor
Author by

RaptorFactor

Updated on March 09, 2020

Comments

  • RaptorFactor
    RaptorFactor about 4 years

    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++);
    

    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).