14

C99 §6.5 Expressions

(1) An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof.

(2) Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.72) Furthermore, the prior value shall be read only to determine the value to be stored.73)

with the footnotes

72) A floating-point status flag is not an object and can be set more than once within an expression.

73) This paragraph renders undefined statement expressions such as

    i = ++i + 1;
    a[i++] = i;

while allowing

    i = i + 1;
    a[i] = i;

where C11 §6.5 changed to (the text of (1) has an addendum):

(1) […] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.

(2) 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.84)

where footnote 84 in C11 is the same as 73 in C99.

I'm a little confused… I read C11 (2) as "[…] either (a different side effect on the same scalar object) or (a value computation using the value of the same scalar object) […]" which seems to not even allow foo = ++i (there is a side effect and we use a value depending on the changed object). I'm not a native speaker, though, so it would be nice if one could tell me how this sentence should be "parsed". I understand C99, but I don't quite understand the wording of C11.

Anyway, the actual question: Is this a change from C99 to C11, or are these wordings equivalent? And if so, why it has been changed? And if not, could someone give an example of an expression which is UB in C99 but not in C11 or vice versa?

haccks
  • 104,019
  • 25
  • 176
  • 264
mafso
  • 5,433
  • 2
  • 19
  • 40

4 Answers4

5

C11 (and also C++11) has completely reworked the wording of sequencing because C11 now has threads, and it had to explain what sequencing between threads that access the same data means. The intention of the committee was to keep things backward compatible to C99 for the case where there is only one thread of execution.

Let's have a look at the C99 version:

  1. Between the previous and next sequence point

  2. an object

  3. shall have

  4. its stored value modified at most once

  5. by the evaluation of an expression.

compared to the new text

If a side effect on

different terminolgie for 4, modifying the stored value

a scalar object

a restriction of the previous wording in 2. The new text only says something about scalar objects

is unsequenced relative to either

unsequenced is a generalization of the concept in 1. that two statements were separated by a sequence point. Think of two threads that modify the same data without using a lock or something similar.

a different side effect on the same scalar object

the object is only allowed be modified once

or a value computation using the value of the same scalar object,

or a read of the value may not appear concurrently to the modification

the behavior is undefined.

The "shall" in 3. is saying this implicitly. All "shall"s lead to UB if they are not fulfilled.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
3

I'm a little confused… I read C11 (2) as "[…] either (a different side effect on the same scalar object) or (a value computation using the value of the same scalar object) […]" which seems to not even allow foo = ++i (there is a side effect and we use a value depending on the changed object).

If you read the standard quote carefully

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.84)

then you will find that your wording should be:

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).

This means that foo = ++i is a defined statement. It is true that there is a side effect on i (on foo also) but nothing is unsequenced here for the object i.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • The two side effects (incrementing `i` and updating `foo`) are unsequenced, but that doesn't cause any problems because they're distinct objects. – Keith Thompson Jan 11 '14 at 19:58
  • Thanks, I begin to understand C11(2). But still, is C99 and C11 equivalent here (the only proof, that it's not, is a counter example)? – mafso Jan 11 '14 at 20:01
  • @KeithThompson; The two side effects are unsequenced but for a separate object (either for `i` or `foo`) it doesn't matter. That's why I wrote *nothing is unsequenced here*. – haccks Jan 11 '14 at 20:03
  • @KeithThompson Isn't the side effect of `++i` sequenced before the value computation of `(++i)`, and therefore sequenced before the modification of `foo`? – dyp Jan 11 '14 at 20:18
  • 1
    @dyp: No, the side effect can occur any time before the next sequence point. – Keith Thompson Jan 11 '14 at 21:01
  • @KeithThompson; Is `b ^= a ^= b` invokes UB in C99 ? (just for curiosity ) – haccks Jan 11 '14 at 21:14
  • Off the top of my head, I'm not sure. – Keith Thompson Jan 11 '14 at 21:23
  • Thanks a lot for the counter example. I'll need some time until I understand everything, and currently, I'm not sure, if your example is valid C11: The _value computations_ are sequenced, of course, but the side effects (updating `a` twice) aren't necessarily, I think. But, as I said, I'm still not sure. Are you? – mafso Jan 12 '14 at 20:26
  • Yes, I am sure. This example is valid in C11. – haccks Jan 12 '14 at 20:28
  • Thanks again for the example, I think, I got it. Sorry if this is annoying, but I still think, your reasoning is wrong (same issue with your answer in the link). As I said, §6.5(2) only guaranties the sequencing of _value computations_. What guaranties your example to work is §6.5.16(2) _The side effect of updating the stored value of the left operand_ [of an assignment operator] _is sequenced after the value computations of the left and right operands_. – mafso Jan 13 '14 at 10:46
  • In my view, both statements are similar. No difference, except 6.5.2 is more concise. – haccks Jan 13 '14 at 12:23
  • I don't think fact that evaluation of an operator's operands are sequenced before the computation of the result makes the swap macro legitimate; while the compiler is guaranteed to compute the *value* of the rightmost `(a) ^= (b)` before it does anything with the leftmost one, I don't think there's any requirement that the actual *store* to `a` must take place at that time. By my understanding, the store could be legitimately deferred long enough to conflict with the one to its left. – supercat Feb 05 '15 at 22:24
  • @supercat; *while the compiler is guaranteed to compute the value of the rightmost `(a) ^= (b)` before it does anything with the leftmost one,*: Ultimately it comes from the sequencing. – haccks Feb 07 '15 at 15:33
2

This is an explanation of foo = ++i but not really an answer to the question.


Prefix increment is defined in terms of compound assignment, see 6.5.3/2

The expression ++E is equivalent to (E+=1)

For assignment in general, there's a guarantee in 6.5.16/3

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.

So foo = ++i is equivalent to foo = (i+=1). The inner i+=1 requires the modification of i to be sequenced after the computation i+1. The resulting value of the expression (i+=1) is specified in 6.5.16/3 as:

An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

It seems as if this requires the value computation of i+=1 to be sequenced after the modification of i, and in C++11, this is even guaranteed explicitly [expr.ass]/1

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

(which is clearer to me, but I know C++ far better than C)

The modification of i is sequenced before the value computation of i+=1, so we don't have UB accessing the value of ++i in foo = ++i (as the value computation of the left and right operands of foo = x are sequenced before the modification of foo).

dyp
  • 38,334
  • 13
  • 112
  • 177
1

As far as I understand it,

If a side effect on a scalar object is unsequenced relative to ... a value computation using the value of the same scalar object

does not apply here because of (1) which states that

The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.

In other words, the result is defined to "come later", i. e. it is sequenced.

glglgl
  • 89,107
  • 13
  • 149
  • 217