Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

Are logical operators evaluated with short circuit?

Do logical operators in the C language are evaluated with the short circuit? Explanation: None.

What is short-circuit evaluation in the case of the and operator?

Short-circuit evaluation, minimal evaluation, or McCarthy evaluation (after John McCarthy) is the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first ...

Which logical operators perform short-circuit evaluation?

Which logical operators perform short-circuit evaluation? Short-circuit evaluation is performed with the not operator.

Can short-circuit evaluation?

Short-Circuit Evaluation: Short-circuiting is a programming concept by which the compiler skips the execution or evaluation of some sub-expressions in a logical expression. The compiler stops evaluating the further sub-expressions as soon as the value of the expression is determined.


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.


Short circuit evaluation, and order of evaluation, is a mandated semantic standard in both C and C++.

If it wasn't, code like this would not be a common idiom

   char* pChar = 0;
   // some actions which may or may not set pChar to something
   if ((pChar != 0) && (*pChar != '\0')) {
      // do something useful

   }

Section 6.5.13 Logical AND operator of the C99 specification (PDF link) says

(4). Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares equal to 0, the second operand is not evaluated.

Similarly, section 6.5.14 Logical OR operator says

(4) Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares unequal to 0, the second operand is not evaluated.

Similar wording can be found in the C++ standards, check section 5.14 in this draft copy. As checkers notes in another answer, if you override && or ||, then both operands must be evaluated as it becomes a regular function call.


Yes, it mandates that (both evaluation order and short circuit). In your example if all functions return true, the order of the calls are strictly from functionA then functionB and then functionC. Used for this like

if(ptr && ptr->value) { 
    ...
}

Same for the comma operator:

// calls a, then b and evaluates to the value returned by b
// which is used to initialize c
int c = (a(), b()); 

One says between the left and right operand of &&, ||, , and between the first and second/third operand of ?: (conditional operator) is a "sequence point". Any side effects are evaluated completely before that point. So, this is safe:

int a = 0;
int b = (a++, a); // b initialized with 1, and a is 1

Note that the comma operator is not to be confused with the syntactical comma used to separate things:

// order of calls to a and b is unspecified!
function(a(), b());

The C++ Standard says in 5.14/1:

The && operator groups left-to-right. The operands are both implicitly converted to type bool (clause 4). The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false.

And in 5.15/1:

The || operator groups left-to-right. The operands are both implicitly converted to bool (clause 4). It returns true if either of its operands is true, and false otherwise. Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.

It says for both next to those:

The result is a bool. All side effects of the first expression except for destruction of temporaries (12.2) happen before the second expression is evaluated.

In addition to that, 1.9/18 says

In the evaluation of each of the expressions

  • a && b
  • a || b
  • a ? b : C
  • a , b

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


Straight from good old K&R:

C guarantees that && and || are evaluated left to right — we shall soon see cases where this matters.


Be very very careful.

For fundamental types these are shortcut operators.

But if you define these operators for your own class or enumeration types they are not shortcut. Because of this semantic difference in their usage under these different circumstances it is recommended that you do not define these operators.

For the operator && and operator || for fundamental types the evaluation order is left to right (otherwise short cutting would be hard :-) But for overloaded operators that you define, these are basically syntactic sugar to defining a method and thus the order of evaluation of the parameters is undefined.