13
#include <stdio.h>

int main(void) {
    int a = 0, b = 0, c = 0;
    ++a || ++b && ++c;
    printf("%d %d %d", a, b, c);
    return 0;
}

The outputs are 1, 0, 0 by gcc 8.1.0. The &&‘s precedence should higher than ||.

Why are the b and c are still 0?

Tim Diekmann
  • 7,755
  • 11
  • 41
  • 69
Joshua Shi
  • 343
  • 1
  • 6

6 Answers6

14

The expression ++a || ++b && ++c is grouped as ++a || (++b && ++c). But, the right hand side of || is only evaluated if ++a is 0, which it isn't.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
13

There are three issues here:

  1. Order of precedence.
  2. Order of evaluation.
  3. Short circuiting of logical operators.

Order of precedence implies that ++a || ++b && ++c is evaluated as ++a || (++b && ++c).

However, due to the short circuiting requirements of logical operators, ++a is evaluated first. Only if that evaluates to false will (++b && ++c) be evaluated. In your case, ++a evaluates to true. Hence, (++b && ++c) is never evaluated.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

The logical OR operator || (as well as the logical AND operator &&) is one of the few operators that perform short circut operation.

Section 6.5.14 of the C standard says the following about the logical OR operator:

4 Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.

Because ++a evaluates to 1, the result of the || operator is guaranteed to be 1 and the right hand side is not evaluated. Also, because && has higher precedence than ||, the right side of the || operator is ++b && ++c, meaning that neither ++b or ++c is evaluated.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

Precedence only controls how expressions are parsed, not how they are evaluated. Arithmetic * has higher precedence than +, so a * b + c is parsed as (a * b) + c. However, each of a, b, and c may be evaluated in any order. The result of a * b must be known before it can be added to the result of c, but that doesn't mean that a * b must be evaluated before c.

Secondly, unlike most operators in C, the || and && operators force left-to-right evaluation. An expression like a || b && c will be parsed as a || (b && c), but a will always be evaluated first, and b && c will only be evaluated if the result of a is 0.

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

As far as precedence goes, x || y && z acts just like x + y * z: the second operator binds more tightly than the first one, and those expressions are equivalent to x || (y && z) and x + (y * z), respectively.

The reason that b and c in the question aren't incremented is because, in addition to precedence, logical operations short circuit: once you've gotten far enough along to know the result, the rest of the expression is skipped. Both || and && evaluate their arguments left-to-right, so in a() || b() and in a() && b(), the call to a() occurs before the call to b().

In simple cases, if a() returns true, then in the expression a() || b() the call to b() will not be executed, because it won't affect the result. Similarly, if a() returns false, then in the expression a() && b(), the call to b() will not be executed.

In the code in the example, the increments to b and c won't be performed, because ++a produces a non-zero value, so the result of the expression is true without needing to evaluate anything after ++a.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
-1

Operator precedence has nothing to do with order of evaluation. Precedence is the priority for grouping different types of operators with their operands.

So, the expression

++a || ++b && ++c;

will be evaluated as

++a || (++b && ++c);

Logical AND and Logical OR operator constitute sequence points and therefore guarantee a particular order of evaluation for their operands which is left to right.

Order of evaluation:

Ordering
......

  • If a sequence point is present between the subexpressions E1 and E2, then both value computation and side effects of E1 are sequenced-before every value computation and side effect of E2

Rules
.....
2) There is a sequence point after evaluation of the first (left) operand and before evaluation of the second (right) operand of the following binary operators: && (logical AND), || (logical OR), and , (comma).

Logical OR operation (expr1 || expr2) employs short-circuiting behavior. That is, expr2 is not evaluated if expr1 is logical 1 (true).

The initial value of a, b and c is 0. In the expression:

++a || ++b && ++c;

++a -> pre-increment a.
That means, the value of the expression ++a is resulting incremented value of a which will be 1. Since, || operator employs short-circuit behavior, the right hand side expression of || will not be evaluated. Hence, you are getting output - 1 0 0.


For better understanding, just try to change the ++a -> a++ in the expression.
The post increment operator also increase the value of operand by 1 but the value of the expression is the operand's original value prior to the increment operation. So, a++ will be evaluated to 0 and because of short-circuit behavior the right hand side expression of || operator (++b && ++c) will be evaluated.

The logical AND operation (expr1 && expr2) also employs short-circuiting behavior. With logical short-circuiting, the second operand, expr2, is evaluated only when the result is not fully determined by the first operand, expr1. That is, expr2 will be evaluated only if expr1 is logical 1 (true) and ++b will result in 1. So, if you do

a++ || ++b && ++c;
^^^

The output would be - 1 1 1.

H.S.
  • 11,654
  • 2
  • 15
  • 32