C++ Short-Circuiting of Booleans

C++ short-circuiting of booleans

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).

What is short-circuit evaluation in C?

The && operator uses lazy evaluation. If either side of the && operator is false, then the whole expression is false.

C checks the truth value of the left hand side of the operator, which in your case is 0. Since 0 is false in c, then the right hand side expression of the operation, (a = b = 777), is never evaluated.

The second case is similar, except that || returns true if the left hand side expression returns true. Also remember that in c, anything that is not 0 is considered true.

Hope this helps.

In C/C++ is it safe to use boolean operator short circuit for control flow without using computed boolean value?

This is called a "discarded-value expression", and it has to be evaluated:

N4296, 5§11:

In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value
expression. The expression is evaluated and its value is discarded.

Short-circuiting of non-booleans

The second expression will evaluate to either 1 or 0.

Quoting the C11 standard draft:

6.5.14 Logical OR operator


  1. The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

So the two expressions are very different, since one of them yields a pointer, and the other one an integer.

Edit:

One of the comments claims that this answer is only valid for c, and @Lightness Races in Orbit is right.

There are also answers that are only correct for c++1, although the only difference with them is that c++ has type bool and then it evaluates this expression as bool instead of int. But apparently there is an important issue with overloading || operator in c++, which prvents short-citcuiting to apply for the object that overloads it.

So for c++ there are more things to consider, but since this question was tagged with both languages tags, then it's necessary to mention at least the differece.

The rule still applies when short-circuiting applies, i.e. the result of the evaluation of the expressions is either 1 or 0 for c and true or false for c++.


1 Like these answers: 1, 2

Short-circuiting on boolean operands without side effects

As others have mentioned, this assembly output is a compiler optimization that doesn't affect program execution (as far as the compiler can tell). If you want to selectively disable this optimization, you need to tell the compiler that your variables should not be optimized across the sequence points in the code.

Sequence points are control expressions (the evaluations in if, switch, while, do and all three sections of for), logical ORs and ANDs, conditionals (?:), commas and the return statement.

To prevent compiler optimization across these points, you must declare your variable volatile. In your example, you can specify

volatile long a;
unsigned long m;
{...}
if (!a && m > 0x002 && m < 0x111) {...}

The reason that this works is that volatile is used to instruct the compiler that it can't predict the behavior of an equivalent machine with respect to the variable. Therefore, it must strictly obey the sequence points in your code.

Do the &= and |= operators for bool short-circuit?

From C++11 5.17 Assignment and compound assignment operators:

The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once.

However, you're mixing up logical AND which does short-circuit, and the bitwise AND which never does.

The text snippet &&=, which would be how you would do what you're asking about, is nowhere to be found in the standard. The reason for that is that it doesn't actually exist: there is no logical-and-assignment operator.

Short Circuit Boolean operators in C (again): doesn't it produce inefficient code by default?

What version of assembler code will an optimizing C compiler usually generate?

This is an evolving question, and compilers have gotten better and better over the years. Good programmers become familiar with the capabilities of their compilers and write code that takes advantage of it. Thus, if active && isEmpty(&list) versus isEmpty(&list) && active is an issue, a good programmer will choose the one that is better for their situation, and/or they may dive into the implementation of isEmpty and see if it can be improved for this.

However, since the compiler is enforced (by the language rules) to generate the short circuit form,…

This is true and not true. The C standard specifies behavior on two levels. The semantics of C are specified using a model of an abstract computer that explicitly does what the standard says. For &&, it says “… the && operator guarantees left-to-right evaluation…,” so it is true that is what the abstract computer does in the model.

But a C implementation does not have to implement that model literally. On the “what is really implemented” level, instead of on the model level, a C implementation only has to match the observable behavior of the model, which is (C 2018 5.1.2.3 6):

  • Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.
  • At program termination, all data written into files shall be identical to the result that execution of the program according to the abstract semantics would have produced.
  • The input and output dynamics of interactive devices shall take place as specified in 7.21.3. The intent of these requirements is that unbuffered or line-buffered output appear as soon as possible, to ensure that prompting messages actually appear prior to a program waiting for input.

Now suppose the C compiler can see the implementation of isEmpty, as it would when inlining it. In this case, it can see all the effects of active && isEmpty(&list). If active && isEmpty(&list) contains no accesses to volatile objects and no writing to files or interacting with devices, then the actual implementation of the expression can be in any order at all, including any ordering of any subparts inside isEmpty, providing the reordering computes the correct result. So, in the actual implementation, it is not true the compiler must guarantee the left-to-right ordering; it merely needs to guarantee the same result.

That correct result is an issue. Maybe active guarantees that evaluation of isEmpty(&list) will not use some null pointer, so active needs to be evaluated “first.” However, if the compiler is inlining isEmpty, it could evaluate parts of isEmpty first, as long as it ensures none of its evaluations cause a problem if active is false.

One thing that can block these sorts of optimizations is that isEmpty might use other functions or objects that the compiler does not have a complete view of, so the compiler is forced to implement the abstract computer more literally in certain respects. This goes back to the good programmer issue—if this part of the program matters, a good programmer will consider their interactions here between the code for isEmpty and what the compiler capabilities are. And that will likely change over the coming years.

In C, is single & and single | valid so as to avoid short circuit? Also please give some examples of utility of same in C#

Here are the answers to your questions:

Is & and | valid in C so that short circuit can be avoided?

No. The & and | operators in C mean different things compared to their C# logical counterparts.

In C, & and | are bitwise operators. They will evaluate both the sides and combine the bits of the resulting values according to the operator. Afterwards, if the resulting value is used in a logical context it will be processed as 0=false, everything else=true.

This is not the same as short-circuit logical operators as C# have.

In C# bool can only be true, false or null. Unlike C 0 is not false and all non-zero value is not true. So short circuit can never take place in C#.

So in C# what is the utility of & and |?

The purpose of & and | as logical operators in C# is to support non-short-circuit evaluation.

Take this example:

// s is string
if (s != null && s.Length > 0) { ... }

Here, if s is indeed null, the value of the first operand is false, hence the whole expression can never be true and thus the second operand, s.Length > 0 is not evaluated.

Contrast to this:

if (s != null & s.Length > 0) { ... }

Observe that I switched to the non-short-circuit & operator here. Here, if s is null, both operands will still be evaluated and the code will throw a NullReferenceException.

In some situations, it may be beneficial and required that you evaluate both sides even if you know the result will never be false regardless of what the second operand says. In those situations, you would use the non-short-circuit operators.


In C, the operators mean this:

  • | = bitwise OR operator
  • & = bitwise AND operator
  • || = logical OR operator that short circuits
  • && = logical AND operator that short circuits

In C#, the operators mean this:

  • | = bitwise OR operator if applied to integers, logical non-short-circuit OR operator if applied to bools
  • & = bitwise AND operator if applied to integers, logical non-short-circuit AND operator if applied to bools
  • || = logical OR operator that short circuits
  • && = logical AND operator that short circuits

Is short-circuiting logical operators mandated? And evaluation order?

Yes, short-circuiting and evaluation order are required for operators || and && in both C and C++ standards.

C++ standard says (there should be an equivalent clause in the C standard):

1.9.18

In the evaluation of the following expressions

a && b
a || b
a ? b : c
a , b

using the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).

In C++ there is an extra trap: short-circuiting does NOT apply to types that overload operators || and &&.

Footnote 12: The operators indicated in this paragraph are the built-in operators, as described in clause 5. When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation, and the operands form an argument list, without an implied sequence point between them.

It is usually not recommended to overload these operators in C++ unless you have a very specific requirement. You can do it, but it may break expected behaviour in other people's code, especially if these operators are used indirectly via instantiating templates with the type overloading these operators.



Related Topics



Leave a reply



Submit