Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the order of execution always the same in C/C++

Tags:

c++

c

Will this code always result in the same result?

return c * (t /= d) * t * t + b;

So I expect:

return ((c * (t / d) ^ 3) + b);

But I am not sure if the compiler can also interpret it as:

return ((c * t * t * (t / d)) + b)

I have searched in the C standard but could not find an answer, I know that x = x++ is undefined but here I am not sure because of the () around the t /= d which I think force the compiler to first calculate that statement.

like image 559
laserbeamer Avatar asked Dec 15 '22 05:12

laserbeamer


2 Answers

I have searched in the C standard but could not find an answer

The thing you're searching for is the sequence point.

Your expression

c * (t /= d) * t * t + b

doesn't contain any sequence points, so the sub-expressions may be evaluated in any relative order.


NOTE that this applies to C, since you mentioned that in the question. You've also tagged the related-but-very different language C++, which has different rules. Luckily, in this case, they give exactly the same result.

The relevant text from the 2014-11-19 working draft PDF:N4296 is

1.9 Program Execution [intro.execution]

...

14 Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

15 Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. — end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent (1.10), the behavior is undefined. [ Note: The next section imposes similar, but more complex restrictions on potentially concurrent computations. — end note ]

So the logic in C++ is that unless things are explicitly sequenced (eg, by a ; separating two full expressions), then they can happen in any order.

As the (second) highlighted section mentions, when two un-sequenced sub-expressions modify the same object (or one modifies and one reads), the behaviour is undefined.

like image 173
Useless Avatar answered Dec 25 '22 00:12

Useless


The above expression, with parenthesis making the order of operations explicit, is as follows:

return ((((c * (t /= d)) * t) * t) + b);

The problem here, however, is that there is no sequence point in this expression. So any of the subexpressions can be evaluated in any order.

For example, the compiler may choose to evaluate the value of t once, then use the original value each place it appears. Conversely, it may first evaluate t /= d which modifies t, then use this modified value anyplace else it appears.

In short, because you are both reading and writing a variable in a single expression without a sequence point, you invoke undefined behavior.

like image 26
dbush Avatar answered Dec 25 '22 00:12

dbush