I was reading my textbook for my computer architecture class and I came across this statement.
A second important distinction between the logical operators '
&&
' and '||
' versus their bit-level counterparts '&
' and '|
' is that the logical operators do not evaluate their second argument if the result of the expression can be determined by evaluating the first argument. Thus, for example, the expressiona && 5/a
will never cause a division by zero, and the expressionp && *p++
will never cause the dereferencing of a null pointer. (Computer Systems: A Programmer's Perspective by Bryant and O'Hallaron, 3rd Edition, p. 57)
My question is why do logical operators in C behave like that? Using the author's example of a && 5/a
, wouldn't C need to evaluate the whole expression because &&
requires both predicates to be true? Without loss of generality, my same question applies to his second example.
The logical NOT ( ! ) operator (logical complement, negation) takes truth to falsity and vice versa. It is typically used with boolean (logical) values. When used with non-Boolean values, it returns false if its single operand can be converted to true ; otherwise, returns true .
The logical-AND operator produces the value 1 if both operands have nonzero values. If either operand is equal to 0, the result is 0. If the first operand of a logical-AND operation is equal to 0, the second operand isn't evaluated. The logical-OR operator performs an inclusive-OR operation on its operands.
Not equals tests whether two values are unequal, so TRUE != FALSE evaluates to TRUE. Like the equality operator, != can also be used with numbers.
Do logical operators in the C language are evaluated with the short circuit? Explanation: None.
Short-circuiting is a performance enhancement that happens to be useful for other purposes.
You say "wouldn't C need to evaluate the whole expression because &&
requires both predicates to be true?" But think about it. If the left hand side of the &&
is false, does it matter what the right hand side evaluates to? false && true
or false && false
, the result is the same: false.
So when the left hand side of an &&
is determined to be false, or the left hand side of a ||
is determined to be true, the value on the right doesn't matter, and can be skipped. This makes the code faster by removing the need to evaluate a potentially expensive second test. Imagine if the right-hand side called a function that scanned a whole file for a given string? Wouldn't you want that test skipped if the first test meant you already knew the combined answer?
C decided to go beyond guaranteeing short-circuiting to guaranteeing order of evaluation because it means safety tests like the one you provide are possible. As long as the tests are idempotent, or the side-effects are intended to occur only when not short-circuited, this feature is desirable.
A typical example is a null-pointer check:
if(ptr != NULL && ptr->value) {
....
}
Without short-circuit-evaluation, this would cause an error when the null-pointer is dereferenced.
The program first checks the left part ptr != NULL
. If this evaluates to false
, it does not have to evaluate the second part, because it is already clear that the result will be false
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With