Compilers and Argument Order of Evaluation in C++

Compilers and argument order of evaluation in C++

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.

How not specify an exact order of evaluation of function argument helps C & C++ compiler to generate optimized code?

I think the whole premise of the question is wrong:

How not specify an exact order of evaluation of function argument helps C & C++ compiler to generate optimized code?

It is not about optimizing code (though it does allow that). It is about not penalizing compilers because the underlying hardware has certain ABI constraints.

Some systems depend on parameters being pushed to stack in reverse order while others depend on forward order. C++ runs on all kinds of systems with all kinds on constraints. If you enforce an order at the language level you will require some systems to pay a penalty to enforce that order.

The first rule of C++ is "If you don't use it then you should not have to pay for it". So enforcing an order would be a violation of the prime directive of C++.

Parameter evaluation order before a function calling in C

No, function parameters are not evaluated in a defined order in C.

See Martin York's answers to What are all the common undefined behaviour that c++ programmer should know about?.

Order of parameter evaluation of function call in GCC

If you are really asking foo(f1(), f2(), f3()) - which is more interesting than foo(1+2, 3+4, 5+6), since adding 1+2 and 3+4 won't have effect whether it is done first or last or in a random order.

Now, unfortunately, you can not rely on f1() and f2() and f3() being called in any particular order - as long as each function is called ONCE, it's fine for the order to be any order:

   f1, f2, f3
f1, f3, f2
f2, f3, f1
f2, f1, f3
f3, f2, f1
f3, f1, f2

(that covers all the permutations for three parameters).

It is entirely up to the compiler which it "thinks is best".

I wrote some code a long time back, and ran into this particular problem - I had something along the lines of:

char foo(char a, char b)
...
if (a =! 'x')
foo(fgetc(f), foo(fgetc(f)));
...

Since I expected the FIRST (left) fgetc() to be called first, and the second fgetc(), I could get the right behaviour. And it worked fine on the school computer. Then I took the code home and tried using it on my home computer. And for some reason it didn't work right. It took me quite some time to figure out that foo() was just being called infinitely, because a was never 'x', which stops the recursion - because 'x' would never appear in the second call.

That was using gcc on both machines, but one was a sparc (school computer) and the one at home was a x86 (386, running OS/2, that's how long ago).

The solution is to break it into several lines:

 char aa = fgetc(f);
char bb = fgetc(f);
foo(aa, foo(bb));

Why doesn't c++ have a specified order for evaluating function arguements?

Why doesn't C++ do it this way?

For starters, C++ isn't a functional programming language.

And the fastest way to evaluate the arguments depends on the implementation and architecture, so the compiler gets to choose. We don't pay for what we don't use, in C++, so if you need to specify an evaluation order yourself then you can do so explicitly with named variables.

Although, continuing the theme of newer standards leaving behind sacred C++ paradigms, C++17 will sadly add some evaluation order guarantees, ruining all of that.

Function argument evaluation order

In this case it does not matter.

By passing szBuffer to a function that accepts a char * (or char const *) argument, the array decays to a pointer. The pointer value is independent of the actual data stored in the array, and the pointer value will be the same in both cases no matter whether the fourth or fifth argument to TextOut() gets fully evaluated first. Even if the fourth argument is fully evaluated first, it will evaluate as a pointer to data -- the pointed-to data is what gets changed, not the pointer itself.

To answer your posed question: the actual order of argument evaluation is unspecified. For example, in the statement f(g(), h()), a compliant compiler can execute g() and h() in any order. Further, in the statement f(g(h()), i()), the compiler can execute the three functions g, h, and i in any order with the constraint that h() gets executed before g() -- so it could execute h(), then i(), then g().

It just happens that in this specific case, evaluation order of arguments is wholly irrelevant.

(None of this behavior is dependent on calling convention, which only deals with how the arguments are communicated to the called function. The calling convention does not address in any way the order in which those arguments are evaluated.)

Order of evaluation in C++ function parameters

No, there's no such guarantee. It's unspecified according to the C++ standard.

Bjarne Stroustrup also says it explicitly in "The C++ Programming Language" 3rd edition section 6.2.2, with some reasoning:

Better code can be generated in the
absence of restrictions on expression
evaluation order

Although technically this refers to an earlier part of the same section which says that the order of evaluation of parts of an expression is also unspecified, i.e.

int x = f(2) + g(3);   // unspecified whether f() or g() is called first

Operator precedence versus order of evaluation

I would prefer an explanation that uses function calls. A function call makes it very obvious that "something needs to be evaluated before applying the operator".

Basic example:

int x = a() + b() * c();

must be calculated as

temp = result_of_b_func_call * result_of_c_func_call
x = result_of_a_func_call + temp

due to multiplication having higher precedence than addition.

However, the evaluation order of the 3 function calls is unspecified, i.e. the functions can be called in any order. Like

a(), b(), c()
or
a(), c(), b()
or
b(), a(), c()
or
b(), c(), a()
or
c(), a(), b()
or
c(), b(), a()

Another basic example would be to explain operator associativity - like:

int x = a() + b() + c();

must be calculated as

temp = result_of_a_func_call + result_of_b_func_call
x = temp + result_of_c_func_call

due to left-to-right associativity of addition. But again the order of the 3 function calls are unknown.

If function calls is not an option, I would prefer something like

x = a * b + c / d

Here it's pretty obvious that there are two sub-expressions, i.e. a * b and c / d. Due to operator precedence both of these sub-expressions must be evaluated before the addition but the order of evaluation is unspecified, i.e. we can't tell whether the multiplication or the division is done first.

So it can be

temp1 = a * b
temp2 = c / d
x = temp1 + temp2

or it can be

temp2 = c / d
temp1 = a * b
x = temp1 + temp2

All we know is that the addition must be last.



Related Topics



Leave a reply



Submit