C++ short-circuiting of booleans
Asked Answered
C

8

12

I'm new to c++ and am curious how the compiler handles lazy evaluation of booleans. For example,

if(A == 1 || B == 2){...}

If A does equal 1, is the B==2 part ever evaluated?

Crosscrosslet answered 25/11, 2009 at 18:39 Comment(5)
wow, that was the quickest 6 responses ever. thanks guys.Crosscrosslet
You could have tested that by creating a function with a side effect (i.e., print something to standard out) and placing it in the second position (assuming that the first condition is false). Also, the documentation tells us that || is a short circuiting operator.Seminar
but then where would be the fun in watching all of these answers flow in?Crosscrosslet
note that it doesn't have anything to do with lazy evaluation. While it's true that lazy evaluating languages make this behavior trivial to implement; in C/C++ case, it's just compiled into the equivalent of a series of nested ifs.Chloro
@Ed: Tests are not a substitute for standards and documentation.Wichita
O
23

No, the B==2 part is not evaluated. This is called short-circuit evaluation.

Edit: As Robert C. Cartaino rightly points out, if the logical operator is overloaded, short-circuit evaluation does not take place (that having been said, why someone would overload a logical operator is beyond me).

Oatmeal answered 25/11, 2009 at 18:40 Comment(3)
My experience is that some compilers will evaluate B==2 when strong optimizations are enabled. Although I've now switched to GCC, I recall MSVC 6 or so would evaluate B==2 prior to A==1 in release mode.Millikan
@Millikan you either wrong or that compiler is buggy, it must not evaluate right side if left is true.Analysand
@Analysand that is not entirely true. The compiler can spot that neither operation has (relevant) side-effects and evaluate them in whatever order it deems optimal as per the as-if rule.Mansfield
V
22

Unless the || operator is overloaded, the second expression will not be evaluated. This is called "short-circuit evaluation."

In the case of logical AND (&&) and logical OR (||), the second expression will not be evaluated if the first expression is sufficient to determine the value of the entire expression.

In the case you described above:

if(A == 1 || B == 2) {...}

...the second expression will not be evaluated because

TRUE || ANYTHING, always evaluates to TRUE.

Likewise,

FALSE && ANYTHING, always evaluates to FALSE, so that condition will also cause a short-circuit evaluation.

A couple of quick notes

  • Short circuit evaluation will not apply to overloaded && and || operators.
  • In C++, you are guaranteed that the first expression will be evaluated first. Some languages do not guarantee the order of evaluation and VB doesn't do short-circuit evaluation at all. That's important to know if you are porting code.
Vignette answered 25/11, 2009 at 18:48 Comment(1)
"VB doesn't do short-circuit evaluation at all"--that's only true with the And and Or operators. But the AndAlso and OrElse operators specifically do perform short-circuit evaluation.Reflexion
B
1

The B==2 part is not evaluated.

Be careful! Don't put something like ++B==2 over there!

Berger answered 25/11, 2009 at 18:42 Comment(0)
V
1

C++ applies short circuiting to Boolean expression evaluation so, the B == 2 is never evaluated and the compiler may even omit it entirely.

Veta answered 25/11, 2009 at 18:42 Comment(2)
Oh come on, this answer was missing so much context it might as well have been an answer saying "potato". Maybe you made a bad assumption because A was capitalized, but it was never specified to be a macro or even a static const. If it's a variable, the compiler would never assume that the clause would be true to the extent that it would omit the B==2 check from being possible within the code. And if you think that should be fundamentally obvious to anyone reading, you've never taught someone their first programming language.Succinctorium
@Succinctorium ... context aside, you cannot assume that the B == 2 branch is ever evaluated and if A is provably a constant expression that is equal to 1 a good compiler will completely omit the branch when instructed to optimize for code size. The code will be compiled but the optimizer is free to strip dead branches if they will never be executed. As for early programmers, it is important to understand basic concepts like what a linker or optimizing compiler does to your code lest you make bad assumptions.Veta
C
1

The compiler handles this by generating intermediate jumps. For the following code:

if(A == 1 || B == 2){...}

compiled to pseudo-assembler, might be:

    load variable A
    compare to constant 1
    if equal, jump to L1
    load variable B
    compare to constant 2
    if not equal, jump to L2
L1:
    ... (complete body of if statement)
L2:
    (code after if block goes here)
Consolidation answered 25/11, 2009 at 18:42 Comment(3)
you don't know that. You compiler might decide that A is always 1 for instance and completely discard that check.Begun
That's true, but that's an optimisation and not relevant for this example.Consolidation
in addition to @shoosh's point, the compiler may also decide that the addition of another point of possible branch misprediction isn't cheaper than just combining the comparisons, and because B has no side-effects the instructions it emits always do both comparisons and only have one branch point.Throw
E
1

This is short-circuit evaluation, as James says. Lazy evaluation is something entirely different.

Escadrille answered 25/11, 2009 at 18:44 Comment(2)
It's not something entirely different. Short-circuit evaluation is a form of lazy evaluation.Oatmeal
Why was the reference to James' answer rejected as an edit?Breuer
F
0

No it's not.

Same with &&, if one is wrong, it doesn't bother evaluating the other one.

Flatways answered 25/11, 2009 at 18:40 Comment(0)
F
0

B == 2 is never evaluated.

See Short-Circuit Evaluation for more information.

Faulk answered 25/11, 2009 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.