3

() has the highest priority, why is it short-circuited?

int a = 1, b = 0;
(--a)&&(b++);

Why is (b++) still short-circuited?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

4 Answers4

4

The expression (--a) uses the prefix operator and evaluates to 0. This is false and the 2nd expression is not evaluated due to short-circuit as you noted.

Allan Wind
  • 23,068
  • 5
  • 28
  • 38
4

I don't find the term "short-circuit" particularly helpful.

It is better to say that && and || have left-to-right order of evaluation. The C standard (6.5.13) actually explains this well:

the && operator guarantees left-to-right evaluation ...
If the first operand compares equal to 0, the second operand is not evaluated.

And that's it. The left operand --a evaluates to 0.


What is the difference between operator precedence and order of evaluation?

In this case, all that matters is order of evaluation. Operator precedence only guarantees that the expression is parsed as expected - which operands that "glue" to which operator.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

To understand consider the following expression

a * b + c * d

If to assume that the operands of the operator + are evaluated from left to right then at first the expression a * b will be evaluated and then the expression c * d.

The assumption relative to the order of evaluations of operands of the operator + is not valid. But it is valid for the operator &&.

So left operand of the expression

(--a)&&(b++);

is evaluated first. And if its value is not equal to 0 then the second operand is evaluated.

From the C Standard (6.5.13 Logical AND operator)

4 Unlike the bitwise binary & 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 equal to 0, the second operand is not evaluated.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

You are right that you can override operator precedence using parenthesis ().

For example, the expression

a && b || c

is equivalent to

(a && b) || c,

because && has a higher precedence than ||. You can override this precedence by changing it to

a && (b || c)

so that now the || has precedence over &&.

However, operator procedence doesn't change the behavior of the individual operators. In particular, both operators will still use short-circuiting. So, even if || has higher precedence than &&, the && operator will still evaluate its left-hand operand before its right-hand operand.

In both of my examples above, the && operator will still evalulate a before evaluating b or (b || c). Operator precedence will only affect whether the right-hand operand of the && operator is the expression b or (b || c).

Therefore, in your example, by writing (--a)&&(b++) instead of --a&&b++, you are merely ensuring that the -- and ++ operators have precedence over the && operator. This is not necessary, because he C language specifies that these operators already have precedence.

In the hypothetical scenario that the C language had instead specified that the && operator had precedence over the -- and ++ operators, then the expression --a&&b++ would be interpreted as --(a&&b)++, and it would be necessary to write (--a)&&(b++) to prevent this interpretation. But this is not the case.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39