Why is "if (i++ && (i == 1))" false where i is an int holding the value 1?

Tahir Sanglikar picture Tahir Sanglikar · Jul 12, 2015 · Viewed 10.6k times · Source
{
    int i = 1;
    if (i++ && (i == 1))
        printf("Yes\n");
    else
        printf("No\n");
}

As per my understanding, in the if condition, first the expression (i==1) will be evaluated which should return 1, and then it is logically anded with 1 which is the value of i, so the expression should return 1 && 1 == 1, but the else part is executed.

Can someone please explain why the else part is executed?

Answer

Jonathan Leffler picture Jonathan Leffler · Jul 12, 2015

No. In C, there's a sequence point between the evaluation of the LHS of the && operator and the evaluation of the RHS, and the increment must take place and be completed before the RHS is evaluated. So, the i++ (equivalent to i++ != 0) is executed and the increment is completed (and the expression evaluates to true), so by the time the RHS is evaluated, i == 2 and hence the overall expression is false and you get 'No' printed. If the LHS of the && operator evaluated to false (0), the RHS would not be evaluated because of the 'short-circuit' property of the && operator.

Only a few operators have the property of having a sequence point between the evaluation of the LHS and RHS: &&, ||, and , (as an operator, not as a separator in an argument list) — and there's ? : too, which isn't a binary operator but which has a sequence point after the condition is evaluated and before either the expression after the ? or the expression after the : is evaluated (of which one or the other, but not both, is always evaluated).

The && and || operators are the only operators with the 'short-circuit' property. The RHS of && is only evaluated if the LHS evaluates to true; the RHS of || is only evaluated if the LHS evaluates to false.


Clarification on Sequence Points

Iwillnotexist Idonotexist correctly asserted:

The C11 standard hasn't done away with sequence points, only the C++11 standard did.

C++11 (ISO/IEC 14882:2011) says:

1.9 Program execution

¶13 Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread (1.10), which induces a partial order among those evaluations. Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [Note: The execution of unsequenced evaluations can overlap. —end note] Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first. —end note]

The term 'sequence point' does not appear in C++11 at all (the only near match is 'sequence pointer').

C11 (ISO/IEC 9899:2011) says:

5.1.2.3 Program execution

¶3 Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread, which induces a partial order among those evaluations. Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. (Conversely, if A is sequenced before B, then B is sequenced after A.) If A is not sequenced before or after B, then A and B are unsequenced. Evaluations A and B are indeterminately sequenced when A is sequenced either before or after B, but it is unspecified which.13) The presence of a sequence point between the evaluation of expressions A and B implies that every value computation and side effect associated with A is sequenced before every value computation and side effect associated with B. (A summary of the sequence points is given in annex C.)

13) The executions of unsequenced evaluations can interleave. Indeterminately sequenced evaluations cannot interleave, but can be executed in any order.

So, C11 does retain sequence points, but adds the 'sequenced before' and related terms using essentially the same terminology as C++11.