Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can b&&0 be optimized

I know that C/C++ uses the short-circuit evaluation to evaluate the expression of boolean. For example, C/C++ will definitely evaluate the operand a before the operand b in the expression a && b, if a is false, b won't be evaluated.

Besides, I know that things like 5==6 may be totally ignored by the compiler because it is a constant expression, which can be evaluated at compile time.

But I don't know if b && 0 can be optimized by compiler? Can compiler say: OK, the evaluation of 0 is much easier than the evaluation of b, and b hasn't any side effect, so I decide to change b && 0 into 0 && b to evaluate 0 first.

like image 916
Yves Avatar asked Mar 14 '26 09:03

Yves


2 Answers

There are two independent problems involved in your question. The first is that when a compiler "sees" that the if condition is always false (due to && 0), it can completely throw away the corresponding branch. Example translation unit:

bool f(int);

int main()
{
  if (f(1) && 0)
    return 1;
}

With enabled optimizations, there will be very likely no machine code generated for the branch. However, the f(1) expression must be still evaluated at runtime, since the compiler cannot prove that the f(1) call has no observable behavior.

Machine code: https://godbolt.org/z/sEMrfh

On the contrary, if the compiler could prove that f(1) had no observable behavior, it could eliminate its call away. This has nothing to do with the order of evaluation, but with the as-if rule instead. Demo translation unit:

static bool f(int i)
{
  int j = i + 1;
  return true;
}

int main()
{
  if (f(1) && 0)
    return 1;
}

Machine code: https://godbolt.org/z/scs3je

like image 151
Daniel Langr Avatar answered Mar 15 '26 22:03

Daniel Langr


The && and || operators guarantee left-to-right evaluation. Evaluation meaning that the compiler has to check the operand for side effects and if any are present, it must execute those. And if the left operand of && evaluates to zero, it will not evaluate the right one.

Consider if(func() && 0) { do_stuff(); }. Even though the && expression can never be true, the function must still be executed. The compiler isn't going to do some strange re-ordering such as 0 && func(), it will rather just replace the whole expression with func();, removing the if and do_stuff() both.

In general, the compiler is specifically not allowed to re-order the evaluation or execution of the operands of && and ||; they have a so-called sequence point between evaluation of the left and the right operand. Which in turn allows code like (ptr=malloc(...)) && (*ptr = x) to be well-defined and not access a null pointer in case malloc fails.

like image 33
Lundin Avatar answered Mar 15 '26 21:03

Lundin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!