0

There was a debate today among some of my colleagues and I wanted to clarify it. It is about the evaluation order and the sequence point in an expression. It is clearly stated in the standard that C/C++ does not have a left-to-right evaluation in an expression unlike languages like Java which is guaranteed to have a sequencial left-to-right order. So, in the below expression, the evaluation of the leftmost operand(B) in the binary operation is sequenced before the evaluation of the rightmost operand(C):

A = B B_OP C

The following expression according, to CPPReference under the subsection Sequenced-before rules(Undefined Behaviour) and Bjarne's TCPPL 3rd ed, is an UB

x = x++ + 1;

It could be interpreted as the compilers like BUT the expression below is said to be clearly a well defined behaviour in C++11

x = ++x + 1;

So, if the above expression is well defined, what is the "fate" of this?

array[x] = ++x;

It seems the evaluation of a post-increment and post-decrement is not defined but the pre-increment and the pre-decrement is defined.

NOTE: This is not used in a real-life code. Clang 3.4 and GCC 4.8 clearly warns about both the pre- and post-increment sequence point.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
iamOgunyinka
  • 1,040
  • 1
  • 9
  • 17
  • In `x = ++x + 1`, the value of `x` on the LHS is not used, therefore it is not UB. OTOH, in `array[x] = ++x`, the value *is* used, therefore UB (as it's not sequenced wrt the modification in `++x`). – dyp Aug 20 '14 at 10:17
  • `C/C++` is not a language. The rules are slightly different for C than for C++. (Also, the rules for C11 differ from C99; and C++11 differs from C++03). – M.M Aug 20 '14 at 10:18
  • [Link to discussion of x = ++x + 1](http://stackoverflow.com/questions/14005508/so-why-is-i-i-1-well-defined-in-c11) – M.M Aug 20 '14 at 10:25

2 Answers2

5

Lets see what the standard says about sequencing:

C++11 5.17/1: the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

So the evaluation of the operands array[x] and ++x are not sequenced with respect to each other. Both use the value of x, and one modifies it, giving undefined behaviour.

(The second example differs by not using the value of x in the left operand; it remains an lvalue).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • If I get the explanation correctly: in both cases(x = ++x + 1 and array[x] = ++x ), the values of *x* in the RHS is read but the side effects is delayed until the value computation and side effects of the LHS operands of the assignment operator. **array[x]** theoretically doesn't *commit its changes* yet, so changes to x shouldn't change the behaviour of the read memory. – iamOgunyinka Aug 20 '14 at 11:11
0

In array[x] = ++x;, there are two value computations on the scalar object x, and one side effect on x.

The value computation of ++x is sequenced relative to its side effect, but the value computation of x in array[x] is not sequenced relative to the side effect of ++x.

So the behavior is undefined.

The difference between x = ++x and array[x] = ++x is that in the former the appearance of x on the LHS is subject to side effect, while in the latter the x on the LHS is subject to value computation.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • Arguably, `x = ++x` also contains two value computations. [intro.execution]/15 states UB if one value computation *uses the value* of the scalar object (and another one modifies it). – dyp Aug 20 '14 at 10:26
  • Spelling this out a bit more, "evaluating" a glvalue (i.e. the left-hand side in this expression) means determining where the memory location is in which the newly-assigned value will be stored. So if the l.h.s is `x`, we already know `x`'s address; we don't depend on the value of `x`. But in `array[x]` we must retrieve the value of `x` to find out which memory location is designated. – M.M Aug 20 '14 at 10:28
  • 1
    @MattMcNabb Huh? Why should `x = ++x` be UB while `x = ++x + 1` is not? – dyp Aug 20 '14 at 10:29
  • @dyp see AndreyT's answer [here](http://stackoverflow.com/questions/14005508/so-why-is-i-i-1-well-defined-in-c11) – M.M Aug 20 '14 at 10:30
  • 1
    @MattMcNabb the side effect of assignment is sequenced after the value computation of the RHS, which is (in this case) sequenced after the side effect of the RHS. – ecatmur Aug 20 '14 at 10:32
  • @ecatmur the side-effect of incrementing `x` is not part of the value computation of the RHS (for `x = ++x` or `x = x++ + 1`); it is unsequenced w.r.t the assignment side-effect. [Further discussion in this DR](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#637) – M.M Aug 20 '14 at 10:34
  • 1
    @MattMcNabb The side-effect of `++x` is sequenced before the value computation of `++x` (effectively, because the value computation of an assignment is sequenced after its side-effect), and the value computation of the RHS of `=` (i.e., of `++x`) is sequenced before the side-effect of `=`. – dyp Aug 20 '14 at 10:42
  • @dyp Please provide a reference as you are contradicting the references I posted in earlier comments, which hold that it is only the use of `++i` as operand of binary-`+` which causes the side-effect to be sequenced-before – M.M Aug 20 '14 at 10:51
  • 1
    Now this is getting confusing, if x = ++x; is a UB, why isn't x = ++x + 1; At least there are 2 value computation, but the side effect of the RHS operand is sequenced after the side effect of LHS operand??? What on earth is the difference? – iamOgunyinka Aug 20 '14 at 10:57
  • @MattMcNabb Unfortunately, I don't exactly see where this is claimed in texts you cited. When lvalue-to-rvalue conversion must be applied is not rigorously specified in the Standard, see e.g. http://stackoverflow.com/q/5099769 and http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1642 Additionally, the Standard uses the sequencing rules to state where UB happens in these kind of cases. And the sequencing rules are rather clear: The value computation of `++x` in `x = ++x` is sequenced before the side-effect of `=`, and the value of the LHS is not used => no sequencing issues. – dyp Aug 20 '14 at 22:12
  • @Josh the difference is that when `++x` is used as operand of `+`, an lvalue-to-rvalue conversion is performed, which (apparently) means that the increment must already have been performed, because `++x` is an lvalue. – M.M Aug 21 '14 at 00:21
  • @dyp Side-effects are not sequenced w.r.t their associated value computation. It is true that the value computation of `++x` is sequenced-before the side-effect of `=`, but not that the side-effect of `++x` is sequenced-before the side-effect of `=`. Your logic would imply that `x = x++` is well-defined (which everyone agrees it isn't) – M.M Aug 21 '14 at 00:31
  • @dyp Quoting from DR637, "In order to value-compute the RHS (++i + 1), it is necessary to first value-compute the lvalue expression ++i **and then do an lvalue-to-rvalue conversion on the result**. This guarantees that the incrementation side-effect is sequenced before the computation of the addition operation". In `i = ++i` it is not necessary to do the lvalue-to-rvalue conversion after the value computation of `++i` . – M.M Aug 21 '14 at 00:37
  • @MattMcNabb Ad first comment: The side-effect of `++x` is sequenced before the value computation of `++x`. This is not true for `x++`. The value computation both sides of `=`, including the RHS `++x`, is sequenced before the side-effect of `=`. As I said, when an lvalue-to-rvalue conversion is required is not well-specified. I would guess that it is required for the RHS of `=`. – dyp Aug 21 '14 at 00:49
  • @dyp the RHS of `=` might not be an lvalue, so it can't require lvalue-to-rvalue conversion. Certainly there is an lvalue-to-rvalue conversion required to compute `++i` in order to find the initial value of `i` , but that is sequenced-before the value computation of `++i` (because that is defined as equivalent to `i += 1`) – M.M Aug 21 '14 at 00:52
  • @MattMcNabb equally either operand of binary `+` might not be an lvalue, but we agree (I think) that lvalue-to-rvalue conversion occurs there. – ecatmur Aug 21 '14 at 08:04