简体   繁体   中英

C++ Language Parsing and Logical Operators's Short-Circuit

When it comes to the short-circuit of the logical operators, according to the Standard in 7.6.14 e 7.6.15 (N4868).

7.6.14 Logical AND operator

[...] the second operand is not evaluated if the first operand is false.

7.6.15 Logical OR operator

[...] the second operand is not evaluated if the first operand evaluates to true.

When this implementation is discussed in Logical Operators Chaining as (Cond1 && Cond2 && Cond3), in my interpretation, the presented is different from my current mental model on how the c++ code parsing/operator binding occurs in compiler-time .

For something as

if (cond1 && cond2 && cond3) {
   //something
}

It is understood as "if cond1 is false, so occurs short-circuit, cond2 and cond3 are not evaluated and the expression is false" .

For me, even if you have the same result, a more accurate expression about how the parsing should works is "The first 'AND' operation is an sub-expression of the second. If cond1 is false, so occurs short-circuit, cond2 is not evaluated and the sub-expression is evaluated to false. Then in the second operation occurs short-circuit, cond3 is not evaluated and this expression is also evaluted to false".

Like:

(cond1 && cond2) && cond3: evaluation of cond1 and short-circuit of sub-expression to false (cond2 is not evaluated)

false && cond3: short-circuit of the full-expression to false (cond3 is not evaluated)


I am worrying about the model in an high level language like C ++ and not the implementation in runtime (the implementations of the compilers seem to be exactly the same as the first expression I showed, if cond1 is false occurs a jump).

The interpretation I did is accurate, pedantic or is incorrect and is inappropriate in this context (It is overthinking)?

You are correct as far as compiler's "mental model" and whoever wrote "if cond1 is false, so the full-expression is false " is correct as far as CPU's "mental model" in this specific case.

On the compiler side, parsing cond1 && cond2 && cond3 results in (using clang -ast-dump )

`-BinaryOperator 0x557a79f02230 <col:1, col:19> 'bool' '&&'
  |-BinaryOperator 0x557a79f021d8 <col:1, col:10> 'bool' '&&'
  | |-ImplicitCastExpr 0x557a79f021a8 <col:1> 'bool' <LValueToRValue>
  | | `-DeclRefExpr 0x557a79f02168 <col:1> 'bool' lvalue Var 0x557a79f01da0 'cond1' 'bool'
  | `-ImplicitCastExpr 0x557a79f021c0 <col:10> 'bool' <LValueToRValue>
  |   `-DeclRefExpr 0x557a79f02188 <col:10> 'bool' lvalue Var 0x557a79f01ec8 'cond2' 'bool'
  `-ImplicitCastExpr 0x557a79f02218 <col:19> 'bool' <LValueToRValue>
    `-DeclRefExpr 0x557a79f021f8 <col:19> 'bool' lvalue Var 0x557a79f01fa8 'cond3' 'bool'

evaluation of this tree starts at the root && at column 19, which must first evaluate its lhs: so it walks down to the && at column 10, which must first evaluate its lhs too: so it walks down to cond1 . If that returned false , the col:10 && returns false also, without visiting the rhs branch, and then the col:19 && also returns false without visiting the rhs branch.

Both gcc and clang as I just tested produced runtime code that is the equivalent of

if (cond1 == false) goto done;
if (cond2 == false) goto done;
if (cond3 == false) goto done;
 return true;
done:
 return false;

So this evaluation is an example of a (very simple) compiler optimization

see https://godbolt.org/z/rYc11PvPb for the AST and the compiled code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM