The C11 standard (ISO/IEC 9899:2011) has introduced a new definition of side effect sequencing within an expression (see related question). The sequence point concept has been complemented with sequenced before and sequenced after relations which are now the basis for all definitions.
Section 6.5 "Expressions", point 2 says:
If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.
Later on, section 6.5.16 "Assignment operators", point 3 states:
The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.
The first quoted paragraph (6.5/2) is supported by two examples (same as in the C99 standard):
a[i++] = i; //! undefined
a[i] = i; // allowed
This can be easily explained with the definitions:
So, the side effect of i++
(LHS) is unsequenced with i
(RHS), which gives undefined behaviour.
i = ++i + 1; //! undefined
i = i + 1; // allowed
This code, however, seems to result in a defined behaviour in both given cases as:
So, the execution of ++i + 1
shall precede the side effect of updating i
, which means that there is not a side effect on a scalar object unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object.
It is easy to explain these examples with the terms and definitions presented by the C99 standard (see related question). But why is i = ++i + 1
undefined according to C11's terminology?
The assignment operator = assigns the value of its right-hand operand to a variable, a property, or an indexer element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-hand operand.
The assignment operators in C and C++ return the value of the variable being assigned to, i.e., their left operand. In your example of a = b , the value of this entire expression is the value that is assigned to a (which is the value of b converted into the type of a ).
Update
I am changing my answer here, this is not well defined in C11 although it is in C++11. The key here is that the result of ++i
is not an lvalue and therefore does not require an lvalue-to-rvalue conversion after ++i
is evaluated and so we can not be assured that the result of ++i
will be read afterwards. Which is different than C++ and so the defect report I originally linked to hinges on this critical fact:
[...] the lvalue expression ++i and then do an lvalue-to-rvalue conversion on the result. guarantees that the incrementation side-effect is sequenced before the computation of the addition operation[...]
we can see this by going to the C11 draft standard section 6.5.3.1
Prefix increment and decrement operators which says:
[...]The expression ++E is equivalent to (E+=1).[...]
and then section 6.5.16
Assignment operators which says (emphasis mine going forward):
An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment,111 but is not an lvalue.[...]
and footnote 111
says:
The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.
There is no requirement to read the object to determine it's value even if it is volatile.
Original Answer
As far as I can tell this is actually well defined and this example was removed from the C++ draft standard which uses similar language. We can see this in 637. Sequencing rules and example disagree which says:
the following expression is still listed as an example of undefined behavior:
i = ++i + 1;
However, it appears that the new sequencing rules make this expression well-defined:
and the resolution was to strike the prefix example and use the postfix example instead which is clearly undefined:
Change the example in 1.9 [intro.execution] paragraph 16 as follows:
i =
++ii++ + 1; // the behavior is undefined
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With