Consider the classical sequence point example:
i = i++;
The C and C++ standards state that the behavior of the above expression is undefined be
Operator precedence and order of evaluation are two different things. Let's have a look at them one by one:
Operator precedence rule: In an expression operands bound tighter to the operators having higher precedence.
For example
int a = 5;
int b = 10;
int c = 2;
int d;
d = a + b * c;
In the expression a + b * c
, precedence of *
is higher than that of +
and therefore, b
and c
will bind to *
and expression will be parsed as a + (b * c)
.
Order of evaluation rule: It describes how operands will be evaluated in an expression. In the statement
d = a>5 ? a : ++a;
a
is guaranteed to be evaluated before evaluation of ++b
or c
.
But for the expression a + (b * c)
, though *
has higher precedence than that of +
, it is not guaranteed that a
will be evaluated either before or after b
or c
and not even b
and c
ordered for their evaluation. Even a
, b
and c
can evaluate in any order.
The simple rule is that: operator precedence is independent from order of evaluation and vice versa.
In the expression i = i++
, higher precedence of ++
just tells the compiler to bind i
with ++
operator and that's it. It says nothing about order of evaluation of the operands or which side effect (the one by =
operator or one by ++
) should take place first. Compiler is free to do anything.
Let's rename the i
at left of assignment be il
and at the right of assignment (in the expression i++
) be ir
, then the expression be like
il = ir++ // Note that suffix l and r are used for the sake of clarity.
// Both il and ir represents the same object.
Now compiler is free to evaluate the expression il = ir++
either as
temp = ir; // i = 0
ir = ir + 1; // i = 1 side effect by ++ before assignment
il = temp; // i = 0 result is 0
or
temp = ir; // i = 0
il = temp; // i = 0 side effect by assignment before ++
ir = ir + 1; // i = 1 result is 1
resulting in two different results 0
and 1
which depends on the sequence of side effects by assignment and ++
and hence invokes UB.