Function call order

What will be the order of the function call in the following expression:

a = f1(23, 14) * f2(12/4) + f3();

      

Does it depend on the compiler?

+3


source to share


5 answers


The order in which each operand is evaluated is not specified in C and C ++, which means that in your case, the order of the function call is not specified according to the standards.



Please note that it is not listed, not . The implementation is defined.

+12


source


Not specified in C and C ++.

Links:

C ++ 03 Standard: Section 5: Expressions, Paragraph 4:



except as noted by [for example, special rules for && and ||], the order in which the operands of individual operators and subexpressions of individual expressions are evaluated, and the order in which side effects occur, is Unspecified .

C99 Standard: Section 6.5:

Grouping of operators and operands is indicated by the syntax .72) Except as noted below (for function calls (), &, ||,?: And comma operators), the order in which subexpressions are evaluated and the order in which side effects occur are undefined .

+6


source


C ++: The standard guarantees that all expressions occurring before a sequence point are evaluated before reaching that sequence point. In your case, there is no sequence point between =

and ;

, so no order is specified.

+4


source


In this case, the order cannot be predicted. It is not compiler dependent, it is not specified; even with the same compiler, you can get different grades.

+3


source


Rather than just saying this is unspecified, end of story, let me explain how this will be evaluated. Most importantly, don't confuse the concept of evaluation order (operands) with the concept of operator precedence, they are different things.

  • The order in which the entire expression itself is evaluated is easy to understand in this case, when we only have basic mathematical operators. But this can be less trivial when other C operators are involved, so always start evaluating the expression by figuring out in what order the subexpressions will be evaluated:

  • Operator precedence rules are guaranteed to be the same for every compiler. They claim that the binary multiplication operator (*) takes precedence over the binary addition operator (+). They both take precedence over the assignment operator (=). This way, it is guaranteed that the first expression f1(23, 14) * f2(12/4)

    will be evaluated first, then the result of that will become the addition operand with f3()

    , and finally the result will be assigned a

    .

  • To illustrate this, the expression equals a = ( (f1(23, 14) * f2(12/4)) + f3() );

    .

  • So we have a subexpression f1(23, 14) * f2(12/4)

    . The order of evaluation in which the operands themselves are evaluated is undefined behavior, meaning that we cannot know if the operand is evaluating f1 or f2 first. The compiler can evaluate them both left-to-right and right-to-left, and there is no need to document how this applies. All we know is that the compiler will evaluate sequentially both left-to-right and right-to-left.

  • Let's assume a particular compiler evaluates from left to right. f1(23, 14)

    will be appreciated first. Then the next question arises: what are the parameters for the function to be evaluated first. The same is true here, the order of evaluation of the function parameters is also not specified. It doesn't matter in this case, since both parameters are integer constants.

  • With left-to-right evaluation order, the compiler will first evaluate (and execute) f1, then f2, and then multiply their results and store them in a temporary, invisible variable. Then it will evaluate f3 and then do the addition and finally assign the result a

    .

An important lesson you learned here is this: Since the order of evaluation of subexpressions is not specified, each subexpression should not contain any side effects that depend on the order of evaluation. In this example, if f1 and f2 were both writing the numbers 1 or 2, respectively, to a global variable, that global variable would have the value 2 at the end if the compiler evalutes from left to right, but 1 if it evaluates from right to left. This code works fine on one compiler, but crashes on another.

0


source







All Articles