1
int a, b;
a = 1;
a = a + a++;
a = 1;
b = a + a++;

printf("%d %d, a, b);

output : 3,2

What's the difference between line 3 and 5?

Jaebum
  • 1,397
  • 1
  • 13
  • 33
  • This looks rather convoluted. I would have expected the output to be 2,2. – blueberryfields Jan 03 '10 at 03:00
  • 3
    Line 3 isn't valid standard C, that's one difference =) – Stephen Canon Jan 03 '10 at 04:20
  • 1
    -1 This code can't work in the way described (the undefined behavior is irrelevant). The value in 'a' is discarded on the second 'a = 1;' (thus a should be '2' because the only code modifying it after that point is the single 'a++'). Furthermore (after a slightly closer look), this code won't even compile as the string in the 'printf' statement is never closed. – Grant Peters Jan 03 '10 at 05:06
  • 1
    @Stephen: Line 5 too isn't valid standard C – Prasoon Saurav Jan 03 '10 at 11:11

4 Answers4

19

What you are doing is undefined.

You can't change the value of a variable you are about to assign to.

You also can't change the value of a variable with a side effect and also try to use that same variable elsewhere in the same expression (unless there is a sequence point, but in this case there isn't). The order of evaluation for the two arguments for + is undefined.

So if there is a difference between the two lines, it is that the first is undefined for two reasons, and line 5 is only undefined for one reason. But the point is both line 3 and line 5 are undefined and doing either is wrong.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
6

What you're doing on line 3 is undefined. C++ has the concept of "sequence points" (usually delimited by semicolons). If you modify an object more than once per sequence point, it's illegal, as you've done in line 3. As section 6.5 of C99 says:

(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. Furthermore, the prior value shall be read only to determine the value to be stored.

Line 5 is also undefined because of the second sentence. You read a to get its value, which you then use in another assignment in a++.

John Feminella
  • 303,634
  • 46
  • 339
  • 357
4

Line 3 is undefined, line 5 is not.

EDIT:

As Prasoon correctly points out, both are UB.

The simple expression a + a++ is undefined because of the following:

  1. The operator + is not a sequence point, so the side effects of each operands may happen in either order.
  2. a is initially 1.
  3. One of two possible [sensible] scenarios may occur:

    1. The first operand, a is evaluated first,

      a) Its value, 1 will be stored in a register, R. No side effects occur.

      b) The second operand a++ is evaluated. It evaluates to 1 also, and is added to the same register R. As a side effect, the stored value of a is set to 2.

      c) The result of the addition, currently in R is written back to a. The final value of a is 2.

    2. The second operand a++ is evaluated first.

      a) It is evaluated to 1 and stored in register R. The stored value of a is incremented to 2.

      b) The first operand a is read. It now contains the value 2, not 1! It is added to R.

      c) R contains 3, and this result is written back to a. The result of the addition is now 3, not 2, like in our first case!

In short, you mustn't rely on such code to work at all.

Alex Budovski
  • 17,947
  • 6
  • 53
  • 58
4

a++ is a post-fix operator, it gets the value of a then increments it.

So, for lines 2,3:
a = 1
a = 1 + 1, a is incremented.
a becomes 3 (Note, the order these operations are performed may vary between compilers, and a can easily also become 2)

for lines 4,5:
a = 1
b = 1 + 1, a is incremented.
b becomes 2, a becomes 2. (Due to undefined behaviour, b could also become 3 of a++ is processed before a)

Note that, other than for understanding how postfix operators work, I really wouldn't recommend using this trick. It's undefined behavior and will get different results when compiled using different compilers

As such, it is not only a needlessly confusing way to do things, but an unreliable, and worst-practice way of doing it.

EDIT: And has others have pointed out, this is actually undefined behavior.

Adam Luchjenbroers
  • 4,917
  • 2
  • 30
  • 35
  • Thx A LOT! xD // that code was just for an educational purpose – Jaebum Jan 03 '10 at 03:12
  • 8
    This answer is incorrect because it does not mention "undefined behaviour", which is what you are invoking. The explanation is bogus, too - I am sorry to say. There is no good explanation because the standard says the behaviour is undefined - anything is legitimate. – Jonathan Leffler Jan 03 '10 at 03:18
  • 3
    Concurrence with Jonathan -- it's not merely that this is "needlessly confusing", but it's actually wrong to do it. The standard does not allow modifying things twice between sequence points. – John Feminella Jan 03 '10 at 03:40
  • 1
    Updated to reflect that this behavior is undefined. The first sequence of events still adequately explains what happened using his compiler. – Adam Luchjenbroers Jan 03 '10 at 04:46
  • 2
    @Adam: Giving explanation of an undefined behavior doesn't make much sense. You should have given just the reason why these expressions invoke undefined behavior. Mark's answer is totally correct. – Prasoon Saurav Jan 03 '10 at 11:17
  • -1, this is undefined behavior according to the standards, full stop. Giving explanation of such a trivial case out of the umpteen possibilities which themselves are compiler specific is ridiculous – rocknroll May 14 '10 at 09:12