views:

391

answers:

10

Why does this code always produce x=2?

unsigned int x = 0;
x++ || x++ || x++ || x++ || ........;
printf("%d\n",x);
+9  A: 

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

Nikolai N Fetissov
|| is a sequence point, as the page you linked to mentions. So this is not undefined behaviour.
Mark Byers
The `||` operator introduces a sequence point, so the expression is not undefined.
John Bode
Whoops, removed seq. points from the answer :)
Nikolai N Fetissov
+30  A: 

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
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
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
@Chuck: It's defined because `||` acts as a sequence point. (6.5.14/4 in the C99 standard.)
jamesdlin
....where is Neil?
jldupont
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
@James McMahon, To my knowledge, when it's incremented isn't defined, just what it returns and what it does to x.
cobbal
Brian Postow
@Brian: ` 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
@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
I stand corrected. Didn't know that `||` counted as a sequence point.
Chuck
John Bode
+5  A: 

|| 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
+11  A: 

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
A: 

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
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
+1  A: 

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
+1  A: 

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
Is this even compilable code?
Zano
no of course not.
John Knoeller
+2  A: 

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
To be precise, you do stop evaluating at the first non-zero value you find.
David Thornley
+1  A: 

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

mjmarsh
+1  A: 

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