Function Parameter Evaluation Order

function parameter evaluation order

C and C++ are two completely different languages; don't assume the same rules always apply to both. In the case of parameter evaluation order, however:

C99:

6.5.2.2 Function calls

...

10 The order of evaluation of the function designator, the actual arguments, and
subexpressions within the actual arguments is unspecified, but there is a sequence point
before the actual call.

[Edit]
C11 (draft):

6.5.2.2 Function calls

...

10 There is a sequence point after the evaluations of the function designator and the actual
arguments but before the actual call. Every evaluation in the calling function (including
other function calls) that is not otherwise specifically sequenced before or after the
execution of the body of the called function is indeterminately sequenced with respect to
the execution of the called function.94)

...

94) In other words, function executions do not ‘‘interleave’’ with each other.

C++:

5.2.2 Function call

...

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.

Neither standard mandates the use of the hardware stack for passing function parameters; that's an implementation detail. The C++ standard uses the term "unwinding the stack" to describe calling destructors for automatically created objects on the path from a try block to a throw-expression, but that's it. Most popular architectures do pass parameters via a hardware stack, but it's not universal.

[Edit]

I am getting confusing information from the books.

This is not in the least surprising, since easily 90% of books written about C are simply crap.

While the language standard isn't a great resource for learning either C or C++, it's good to have handy for questions like this. The official™ standards documents cost real money, but there are drafts that are freely available online, and should be good enough for most purposes.

The latest C99 draft (with updates since original publication) is available here. The latest pre-publication C11 draft (which was officially ratified last year) is available here. And a publicly availble draft of the C++ language is available here, although it has an explicit disclaimer that some of the information is incomplete or incorrect.

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

What is the order of evaluation of function arguments java

The evaluation of arguments is described by JLS 15.12.4.2.

An excerpt:

The argument expressions, if any, are evaluated in order, from left to
right. If the evaluation of any argument expression completes
abruptly, then no part of any argument expression to its right appears
to have been evaluated, and the method invocation completes abruptly
for the same reason. The result of evaluating the j'th argument
expression is the j'th argument value, for 1 ≤ j ≤ n.

Applying this to your case the evaluation order is:

ExampleFunction(new ExampleObject("Test", new ExampleObject("Test2")));
- new ExampleObject("Test", new ExampleObject("Test2"))
- - "Test"
- - new ExampleObject("Test2")
- - - "Test2"

This is the order in which the arguments are called for evaluation. This means in turn that to evaluate new ExampleObject("Test", new ExampleObject("Test2")) first new ExampleObject("Test2") will be evaluated.

What is the order of evaluation for function arguments in Javascript?

All the operators in JavaScript evaluate their operands left-to-right, including the function call operator. First the function to call is evaluated then the actual parameters in left-to-right order.

Section 11.2.3 is the relevant spec section.

11.2.3 Function Calls

...

2 Let func be GetValue(ref).

3 Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).

...

and you can see that the ArgumentList production is left-recursive

11.2.4 Argument lists

...

The production ArgumentList : ArgumentList , AssignmentExpression is evaluated as follows

and ArgumentList is evaluated before AssignmentExpression in the following verbiage..

Under EcmaScript 3 some of the comparison operators (<, <=, >, >=) evaluated right to left since a<=b was defined in terms of !(b<a), but that was widely recognized as a spec error, major interpreters did not implement it that way, and it was fixed in EcmaScript 5.

From the language spec:

11.8.5 The Abstract Relational Comparison Algorithm # Ⓣ

The comparison x < y, where x and y are values, produces true, false, or undefined (which indicates that at least one operand is NaN). In addition to x and y the algorithm takes a Boolean flag named LeftFirst as a parameter. The flag is used to control the order in which operations with potentially visible side-effects are performed upon x and y. It is necessary because ECMAScript specifies left to right evaluation of expressions. The default value of LeftFirst is true and indicates that the x parameter corresponds to an expression that occurs to the left of the y parameter’s corresponding expression. If LeftFirst is false, the reverse is the case and operations must be performed upon y before x. Such a comparison is performed as follows:

What is the order of function arguments evaluation and structs initialization in Rust?

The order used to be unspecified, but it's now left-to-right:

Many expressions contain sub-expressions, called the operands of the expression.

and:

The operands of these expressions are evaluated prior to applying the effects of the expression. Expressions taking multiple operands are evaluated left to right as written in the source code.

C++ forcing function parameter evaluation order

The semi-colon that separates statements imposes a "happens before" relation.
auto && a = increment() must be evaluated first. It is guaranteed. The returned temporary will be bound to the reference a (and its lifetime extended) before the second call to increment.

There is no UB. This is the way to force an evaluation order.

The only gotcha here is if increment returned a reference itself, then you'd need to worry about lifetime issues. But if there was no lifetime issues, say if it returned a reference to count, there still would not be UB from the imposed evaluation of a and then b.

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

What is the evaluation order of function arguments?

The source of confusion and different output is the order of evaluation of the arguments.

Look at your example:

m("A", a, SetAI(&a))

This is a function call, the function value and arguments are evaluated in the usual order:

Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
For example, in the (function-local) assignment

y[f()], ok = g(h(), i()+x[j()], <-c), k()

the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.

So basically the spec only guarantees that function calls and communication
ops happen from left-to-right.

Your call has arguments "A", a and SetAI(&a). There is no guarantee if the second argument a is evaluated before the &a param passed to SetAI(), and this very much matters because SetAI() modifies a. Since the order is not guaranteed, you can't rely on which will be evaluated first, both order is valid by the spec.

If you make the evaluation explicit by doing a copy of the struct before, you get the same result:

a := A{}
aCopy := a
m("A", aCopy, SetAI(&a))
b := B{}
bCopy := b
m("B", bCopy, SetBI(&b))

This will output (try it on the Go Playground):

A: {0 } {10 }
B: {0} {10}

Or if you want the function call to be evaluated first:

a := A{}
ap := SetAI(&a)
m("A", a, ap)
b := B{}
bp := SetBI(&b)
m("B", b, bp)

This will output 10 for each cases (try this one on the Go Playground):

A: {10 } {10 }
B: {10} {10}

Problem with order of evaluation in parameter pack expansion

For example, we can use an intermediate std::tuple to force the order of evaluation:

template<typename TR, typename ... TArgs>
TR Bar(std::istream &s, TR f(TArgs...) )
{
std::tuple<TArgs...> args{Parse<TArgs>(s)...};
return std::apply(f, std::move(args));
}

In contrast to function arguments, the order of evaluation of arguments in a braced list is fixed by their order in that list, [dcl.init.list/4]:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions, are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. ]



Related Topics



Leave a reply



Submit