15

Why does the following compile in C++?

int phew = 53;
++++++++++phew ;

The same code fails in C, why?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Jatin
  • 161
  • 1
  • 4
  • Adding C++0x tag just for fun. :) – Prasoon Saurav Sep 11 '10 at 15:10
  • 1
    There must be a standard question we can reference for this type of question. So all questions (that we get this time of year from new college students) can just be quickly closed and marked read this. – Martin York Sep 11 '10 at 16:04

2 Answers2

28

Note: The two defect reports DR#637 and DR#222 are important to understand the below's behavior rationale.


For explanation, in C++0x there are value computations and side effects. A side effect for example is an assigment, and a value computation is determining what an lvalue refers to or reading the value out of an lvalue. Note that C++0x has no sequence points anymore and this stuff is worded in terms of "sequenced before" / "sequenced after". And it is stated that

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, the behavior is undefined.

++v is equivalent to v += 1 which is equivalent to v = v + 1 (except that v is only evaluated once). This yields to ++ (v = v + 1) which I will write as inc = inc + 1, where inc refers to the lvalue result of v = v + 1.

In C++0x ++ ++v is not undefined behavior because for a = b the assignment is sequenced after value computation of b and a, but before value computation of the assignment expression. It follows that the asignment in v = v + 1 is sequenced before value computation of inc. And the assignment in inc = inc + 1 is sequenced after value computation of inc. In the end, both assignments will thus be sequenced, and there is no undefined behavior.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 3
    Good answer. Similarly `int a=4; ++a=5;` would not invoke UB in C++0x, right? – Prasoon Saurav Sep 11 '10 at 15:09
  • @Prasoon yes. It would set `a` to 5. Likewise `a = ++a;` will not be UB, but `a = a++;` will be UB. – Johannes Schaub - litb Sep 11 '10 at 15:13
  • @Johannes : Cool :-). The world is changing. – Prasoon Saurav Sep 11 '10 at 15:16
  • @Johannes : What about `int a=4,b; b = a + a++ ;`, that would be UB or not. Lets see, addition of `a` and `a++` is sequenced before assignment, but hey order of evaluation is still unspecified, is it?. Phew! this is confusing. – Prasoon Saurav Sep 11 '10 at 15:34
  • 3
    @Johannes: I don't understand why `a = ++a` does not invoke undefined behavior, but `a = a++` does. What happened to "except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified"? – Daniel Trebbien Sep 11 '10 at 15:35
  • 5
    @Daniel, the second does invoke undefined behavior because the modification to a in "a++" is not sequenced before, but *after* the value computation of "a++" (naturally, because you want it to yield the old value). Thus the assignment and the modification in "a++" is not sequenced relative to each other. The text you quoted is now worded as "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced." – Johannes Schaub - litb Sep 11 '10 at 15:53
  • 3
    @Prasoon, the modification to a in "a++" is sequenced after value computation of "a++". The two a's in "a + a++" are not sequenced in any way, neither their value computations, nor their side effects. So you have a side effect (modification to a) that is unsequenced relative to a value computation to that a (the first operand), and so you have UB. – Johannes Schaub - litb Sep 11 '10 at 15:59
  • 1
    a = a++; the steps involved are a) value computation of lvalue of 'a' (lhs) b) value computation of lvalue of 'a' (rhs), c) side effect of ++, d) side effect of assignment. Do you mean that in C++0x steps (d) and (c) are unsequenced? – Chubsdad Sep 12 '10 at 05:31
  • 1
    But given a = ++a, since (c) happens before (d), the two side effects are sequenced on the same scalar i.e. 'a' and hence the expression is well-formed? – Chubsdad Sep 12 '10 at 05:33
  • Two clarifications: Value computation of assignment operator includes steps (a), (b) and (c). (d) is a side effect of assignment operator. – Chubsdad Sep 12 '10 at 12:08
  • and the second clarification: 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, the behavior is undefined. - The example discussed above is about side effects being unsequenced with respect to another side effect. Is there an example of 'side effect being unsequenced with respect to value computation using the value of the same scalar object (the second 'or' clause in the statement) – Chubsdad Sep 12 '10 at 12:09
  • @Chubsdad For the first one, note that value computation alone does not *imply* side effects or such (see 1.9/12 - it's "Evaluation" that in generally does). It's just that for an assignment expression, its value computation is sequenced after (c), (a) and (b) (the "sequenced before" relation is transitive). – Johannes Schaub - litb Sep 12 '10 at 12:22
  • 1
    For your second clarification - this was phrased in C++03 using the slender "Furthermore, the prior value shall be accessed only to determine the value to be stored.", which was hardly decisive. C++0x replaces it with what you quoted, and includes orders where necessary. For instance in `a++`, the previous value of "a" is accessed to determine the value being stored, so C++0x induces an order into this. But for "a + a++", this is not the case with respect to the first "a", so it's not ordered and it becomes undefined. This shows a strong point of the C++0x wording. It's much more reliable. – Johannes Schaub - litb Sep 12 '10 at 12:25
  • @Daniel please consider my new answer with the two DR links. They will show that both `a = ++a` and `++ ++ a` is defined behavior and is intended to be so. – Johannes Schaub - litb Oct 10 '10 at 14:02
  • @Chubsdad update ^^ (found two DRs that clarify this and support this answer). – Johannes Schaub - litb Oct 10 '10 at 14:03
  • @Johannes : Excellent find. You should probably show `DR637` to `James Kanze` who made all of us(excluding you) think that he was right all the time. `:-)` – Prasoon Saurav Oct 10 '10 at 14:40
  • Your explanation for `++++v` to be well defined is not convincing. C++11 says that: *The side effect of the built-in preincrement and predecrement operators is sequenced before its value computation.* and that make more sense in this case. – haccks Feb 28 '15 at 15:19
  • @haccks I do not understand what you are saying – Johannes Schaub - litb Feb 28 '15 at 15:36
  • I am saying that the reason you explained that `++++v` is well defined is seem confusing to me. As per your explanation `i = ++i` would be well defined (which is not) in C11 too because it says that: *An assignment expression has the value of the left operand after the assignment*. – haccks Feb 28 '15 at 15:51
  • @JohannesSchaub-litb for "a = b the assignment is sequenced after value computation of b and a",I think no value computation of a(single indentity) here because if it is necessary to invoke value computation of a,then the `a=++a` would invoke UB in c++11,since the modification in "++a" and the value computation in "a"(the left hand operand) relative to each other are unsequenced,so ,theres' no value computation for single `a`,Do you agree? – xmh0511 Mar 11 '20 at 02:10
  • @JohannesSchaub-litb I have seen that answer ,exactly,But for this answer,I hava cavilled to say that this answer would make misunderstand for "value computation" ,if add note for "value computation",it will be perfectly – xmh0511 Mar 12 '20 at 02:04
15

That is because in C++ pre-increment operator returns an lvalue and it requires its operand to be an lvalue.

++++++++++phew ; in interpreted as ++(++(++(++(++phew))))

However your code invokes Undefined Behaviour because you are trying to modify the value of phew more than once between two sequence points.

In C, pre-increment operator returns an rvalue and requires its operand to be an lvalue. So your code doesn't compile in C mode.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 2
    @Prasoon: Not to second guess you, I am just curious to read about what you said; "you are trying to modify the value of phew more than once between two sequence points". Can you provide an annotation to this part of the standard so I can read more about this? – Merlyn Morgan-Graham Sep 11 '10 at 07:10
  • 3
    @Merlyn Morgan-Graham : Read this article by Steve Summit: http://c-faq.com/expr/seqpoints.html . – Prasoon Saurav Sep 11 '10 at 07:12
  • `Commentary` This specification only needs to be followed exactly when there is more than one access between sequence points, or for objects declared with the volatile storage class. As far as the developer is concerned, a modification occurs. As long as the implementation delivers the expected result, it is free to do whatever it likes. – Prasoon Saurav Sep 11 '10 at 07:29
  • 2
    Just to be clear, `++++i` is well-defined for user-defined types, right? – fredoverflow Sep 11 '10 at 09:29
  • 2
    @FredOverflow: Yes because function call introduces a sequence point. :) – Prasoon Saurav Sep 11 '10 at 09:36
  • I cannot quote the standard, but I believe that the behavior is well defined. The standard requires an specific order of execution. Consider that you had `int & f( int & x ) { return ++x; }` and the call: `int x = 0; f( f( f( x ) ) );` The inner `f` must be executed *before* the middle `f` and that is guaranteed to be performed before the external `f` call. The semantics if pre-increment *require* the increment to be performed before the value is yielded. On the other hand, `int x = 0; int y = ++x + x++;` is undefined as the relative order of execution of the pre and post increment undefined. – David Rodríguez - dribeas Sep 11 '10 at 10:25
  • @David: §5/4: "Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression." I think Prasoon is right, although it would almost be hard to write a compiler so bad as to get it wrong. – Potatoswatter Sep 11 '10 at 13:54
  • @Potatoswatter: I'd guess that the simple mistake you could make in writing the compiler would be to inline the `operator++`, and then to apply optimisations to the result as if it were a single expression, without somehow annotating the inlined code to retain the sequence point. It's a fairly fundamental error, since if you got it wrong in this case I bet the optimiser would incorrectly coalesce/reorder statements in other cases too, but I think it's an omission rather than a comission... – Steve Jessop Sep 11 '10 at 14:24
  • 9
    This is only UB in C++03 though. It's valid in C++0x. – Johannes Schaub - litb Sep 11 '10 at 14:24
  • 1
    @Johannes: What is changing in C++0x that makes this no longer UB? – Daniel Trebbien Sep 11 '10 at 15:03
  • @Daniel see my answer for an explanation – Johannes Schaub - litb Sep 11 '10 at 15:04