12

Why does this code always produce x=2?

unsigned int x = 0;
x++ || x++ || x++ || x++ || ........;
printf("%d\n",x);
James McMahon
  • 48,506
  • 64
  • 207
  • 283
user397232
  • 1,750
  • 6
  • 21
  • 30

10 Answers10

30

the 1st x++ changes x to 1 and returns 0
the 2nd x++ changes x to 2 and returns 1

at which point the or short circuits, returns true, and leaves x at 2.

cobbal
  • 69,903
  • 20
  • 143
  • 156
  • 2
    Incidentally: unsigned int x = 0; ++x || ++x || ++x || ++x || ........; printf("%d\n",x); would give 1 as the first ++x would change x to 1 and return x, short-circuiting happens and nothing more is done. – ridecar2 Jan 14 '10 at 19:48
  • 1
    Incidentally, I'm pretty sure this is undefined behavior. Your description of why it would yield 2 is right, but I don't believe it's guaranteed to work that way — you're not supposed to change a variable more than once in a statement The variable could not be incremented until after the whole expression is finished, in which case `x` would always appear to be 0. – Chuck Jan 14 '10 at 19:48
  • 12
    @Chuck: It's defined because `||` acts as a sequence point. (6.5.14/4 in the C99 standard.) – jamesdlin Jan 14 '10 at 19:49
  • Cobbal, to make it clearer, you should write your answer as, returns 0 and then changes x to 1. Making it clearing that the expression is incremented post Boolean evaluation. – James McMahon Jan 14 '10 at 19:54
  • @James McMahon, To my knowledge, when it's incremented isn't defined, just what it returns and what it does to x. – cobbal Jan 14 '10 at 20:05
  • @Jamesdin, @cobbal is correct. The thing that isn't defined is when the increment happens, only what order the return statements happen is defined. So, for example, x = 1; x ++ && x ++ && x ++ && ... is undefined by the spec. because it could be that x gets incremented from 1 to 2 many many times, or it could be that each time it gets incremented again, or several other cases... – Brian Postow Jan 14 '10 at 20:12
  • @Brian: `&&` and `||` are sequence points; the expression on the left is fully evaluated before the expression on the right is even considered (or discarded, in the case of short-circuiting). This is well-defined behavior. Compare to `,` and `;` which are also sequence points. – ephemient Jan 14 '10 at 20:17
  • @Brian, that's not undefined. All increments are done. And all increments happen one after each other. Leaving `x` with value `1 + N` with `N` being the count of operands. Of course, if you have written more than `UINT_MAX` operands, all operands after operand `UINT_MAX + 1` are not executed anymore since that one evaluates to `0`. – Johannes Schaub - litb Jan 14 '10 at 20:28
  • I stand corrected. Didn't know that `||` counted as a sequence point. – Chuck Jan 14 '10 at 22:18
  • 1
    For the record, sequence points occur at the end of a full expression (initializer, expression statement, the expression in a return statement, and control expressions in conditional, iterative, or switch statements), after the first operand of `&&`, `||`, `?:`, or the comma operator, and after the evaluation of the arguments and function expression in a function call. – John Bode Jan 14 '10 at 23:07
11

x++ || x++ || x++ || x++ || ........;

  • First x++ evaluates to 0 first for the conditional check, followed by an increment. So, first condition fails, but x gets incremented to 1.
  • Now the second x++ gets evaluated, which evaluates to 1 for the conditional check, and x gets incremented to 2. Since expression evaluates to 1 (true), there's no need to go further.
Sudhanshu
  • 2,691
  • 1
  • 18
  • 25
9

Because of short circuit in boolean expression evaluation and because || is a sequence point in C and C++.

Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
5

|| short-circuits. Evaluated from left, when a true value is found (non-zero) it stops evaluating, since the expression now is true and never can be false again.

First x++ evaluates to 0 (since it's post-increment), second to 1 which is true, and presto, you're done!

Zano
  • 2,595
  • 27
  • 33
2

When you're evaluating "a || b || c || d || e || ..." you can stop evaluating at the first non-zero value you find.

The first "x++" evaluates to 0, and increments x to 1, and evaluating the expression continues. The second x++ is evaluated to 1, increments x to 2, and at that point, you need not look at the rest of the OR statement to know that it's going to be true, so you stop.

slacy
  • 11,397
  • 8
  • 56
  • 61
1

Because logical OR short-circuits when a true is found.

So the first x++ returns 0 (false) because it is post-increment. (x = 1) The second x++ returns 1 (true) - short-circuits. (x = 2)

Prints x = 2;

RC.
  • 27,409
  • 9
  • 73
  • 93
1

Because of early out evaluation of comparisons.

This is the equivalent of

 0++ | 1++

The compiler quits comparing as soon as x==1, then it post increments, making x==2

John Knoeller
  • 33,512
  • 4
  • 61
  • 92
1

Because the first "x++ || x++" evaluates to "true" (meaning it is non zero because "0 || 1" is true. Since they are all logical OR operators the rest of the OR operations are ignored.

Mike

Mike Marshall
  • 7,788
  • 4
  • 39
  • 63
1

The || operator evaluates the left-hand expression, and if it is 0 (false), then it will evaluate the right-hand expression. If the left hand side is not 0, then it will not evaluate the right hand side at all.

In the expression x++ || x++ || x++ || ..., the first x++ is evaluated; it evaluates to 0, and x is incremented to 1. The second x++ is evaluated; it evaluates to 1, and x is incremented to 2. Since the second x++ evaluated to a non-zero value, none of the remaining x++ expressions are evaluated.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

trying replacing || with |.--

It is the short circuiting of logical operators.

It's the same reason when you do

if (returns_true() || returns_true()){ }

returns_true will only get called once.

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • 2
    Since `||` is a sequence point and `|` isn't, if you replace `||` with `|`, you'll be invoking undefined behavior, and that won't really tell you anything. – jamesdlin Jan 14 '10 at 19:46