This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 6 years ago.
I always wondered about something and couldn`t find an answer somewhere else. If I have this piece of code:
if ((cond1) &&(cond2) && (cond 3) && (cond 4))
{
// do something
}
Let`s say the first condition is false, then my program will verify the other conditions too, or just skip verifying them?
But if I have
if ((cond1) ||(cond2) || (cond 3) || (cond 4))
{
// do something
}
and cond 1 is true, will my program go instantly on the if part or continue to verify the other conditions too?
Quoting C11 standard, chapter §6.5.13, Logical AND operator (emphasis mine)
Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation;
if the second operand is evaluated, there is a sequence point between the evaluations of
the first and second operands. If the first operand compares equal to 0, the second
operand is not evaluated.
So, if the first condition (LHS operand) evaluates to false, the later conditions, i.e., RHS operand of the && is not evaluated.
Similarly (Ironically, rather), for Logical "OR" operator,
Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the
second operand is evaluated, there is a sequence point between the evaluations of the first
and second operands. If the first operand compares unequal to 0, the second operand is
not evaluated.
In C both && and || "sort-circuit", meaning if evaluation of the left operand is enough to determine the outcome then the right operand is not evaluated.
Related
() has the highest priority, why is it short-circuited?
int a = 1, b = 0;
(--a)&&(b++);
Why is (b++) still short-circuited?
I don't find the term "short-circuit" particularly helpful.
It is better to say that && and || have left-to-right order of evaluation. The C standard (6.5.13) actually explains this well:
the && operator guarantees left-to-right evaluation ...
If the first operand compares equal to 0, the second
operand is not evaluated.
And that's it. The left operand --a evaluates to 0.
What is the difference between operator precedence and order of evaluation?
In this case, all that matters is order of evaluation. Operator precedence only guarantees that the expression is parsed as expected - which operands that "glue" to which operator.
The expression (--a) uses the prefix operator and evaluates to 0. This is false and the 2nd expression is not evaluated due to short-circuit as you noted.
To understand consider the following expression
a * b + c * d
If to assume that the operands of the operator + are evaluated from left to right then at first the expression a * b will be evaluated and then the expression c * d.
The assumption relative to the order of evaluations of operands of the operator + is not valid. But it is valid for the operator &&.
So left operand of the expression
(--a)&&(b++);
is evaluated first. And if its value is not equal to 0 then the second operand is evaluated.
From the C Standard (6.5.13 Logical AND operator)
4 Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; if the second operand is evaluated, there
is a sequence point between the evaluations of the first and second
operands. If the first operand compares equal to 0, the second operand
is not evaluated.
You are right that you can override operator precedence using parenthesis ().
For example, the expression
a && b || c
is equivalent to
(a && b) || c,
because && has a higher precedence than ||. You can override this precedence by changing it to
a && (b || c)
so that now the || has precedence over &&.
However, operator procedence doesn't change the behavior of the individual operators. In particular, both operators will still use short-circuiting. So, even if || has higher precedence than &&, the && operator will still evaluate its left-hand operand before its right-hand operand.
In both of my examples above, the && operator will still evalulate a before evaluating b or (b || c). Operator precedence will only affect whether the right-hand operand of the && operator is the expression b or (b || c).
Therefore, in your example, by writing (--a)&&(b++) instead of --a&&b++, you are merely ensuring that the -- and ++ operators have precedence over the && operator. This is not necessary, because he C language specifies that these operators already have precedence.
In the hypothetical scenario that the C language had instead specified that the && operator had precedence over the -- and ++ operators, then the expression --a&&b++ would be interpreted as --(a&&b)++, and it would be necessary to write (--a)&&(b++) to prevent this interpretation. But this is not the case.
I have learnt that logical operator are guaranteed that their evaluation are from left-to right but I was wondering what are the order of evaluation of comparison operator. For instance expression1 < expression2 in other words is it guaranteed that expression1 will be first evaluated before expression2.
According to the standard:
J.1 Unspecified behavior
The following are unspecified:....
— The order in which subexpressions are evaluated and the order in which side effects
take place, except as specified for the function-call (), &&, ||, ?:, and comma
operators (6.5).
Generally speaking, the order of evaluation of subexpressions within an expression is undefined.
The only place where there is an order, i.e. sequence points, is the || (logical OR), && (logical AND), , (comma), and ?: (ternary) operators.
In the case of &&, if the expression on the left evaluates to false (i.e. 0), the result is known to be false and the right side is not evaluated. Similarly for || if the expression on the left evaluates to true (i.e. not 0), the result is known to be true and the right side is not evaluated.
For the ternary operator, the conditional is evaluated first. If it evaluates to true then only the middle part is evaluated, otherwise only the third part is evaluated.
For the comma operator, the left side is evaluated first, then the right side.
From the C standard:
6.5.13.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.
...
6.5.14.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.
...
6.5.15.4 The first operand is evaluated; there is a sequence point after its evaluation. The second operand is evaluated only if the
first compares unequal to 0; the third operand is evaluated only if
the first compares equal to 0; the result is the value of the second
or third operand (whichever is evaluated), converted to the type
described below. If an attempt is made to modify the result of a
conditional operator or to access it after the next sequence point,
the behavior is undefined.
....
6.5.17.2 The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its
evaluation. Then the right operand is evaluated; the result has its
type and value. If an attempt is made to modify the result of a comma
operator or to access it after the next sequence point, the behavior
is undefined.
No, the spec does not mention the order of evaluation for the operand of relational operators. It's unspecified.
Just to add, relational operators are left-to-right associative.
This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 6 years ago.
Let's take this C-code example:
int ID = 0;
if( (Check(&ID) == ERROR)
||(ID == -1)
){
return ERROR;
}
Do you have any guarantee that (Check(&ID) == ERROR) is checked before (ID == -1) ?
(ID = -1 would be an error-state, set by the function Check)
Yes you do. For an expression of the form x || y, y is only evaluated if x evaluates to 0.
This is called short-circutting, and also applies to &&.
Your parentheses are also superfluous: the same applies to the equivalent (and, in my opinion, clearer)
if (Check(&ID) == ERROR || ID == -1)
Yes, because there is a sequence point between evaluation of first and second operand of || operator.
N1570 5.1.2.3 Program execution, paragraph 3 says:
The presence of a sequence point
between the evaluation of expressions A and B implies that every value computation and
side effect associated with A is sequenced before every value computation and side effect
associated with B.
N1570 6.5.14 Logical OR operator, paragraph 4 says:
Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the
second operand is evaluated, there is a sequence point between the evaluations of the first
and second operands. If the first operand compares unequal to 0, the second operand is
not evaluated.
This question already has answers here:
Why does "++x || ++y && ++z" calculate "++x" first, even though operator "&&" has higher precedence than "||"
(11 answers)
Closed 9 years ago.
x = y = z = 1;
z = ++x||++y&&++z;
operator precedence is as follows --
(pre-increment) > && > ||
so answer should be--
1. 2||2 && 2
2. 2||1
3. 1
print x,y,z should be 2,2,1
but, answer is 2,1,1.
Precedence is not the same as order of evaluation. Precedence simply determines what operands and operators belong together. The exact order of evaluation is unspecified except with the logical operators, which are evaluated in strict left-to-right order to enable short-circuiting.
So because && has higher precedence, the variables are first grouped as follows:
(++x) || (++y && ++z)
Then, following left-to-right order, ++x is evaluated. Given that ++x is true, it is known that the entire expression is true. So expression evaluation is short-circuited. (++y && ++z) never gets evaluated. Hence y and z never get incremented.
Expressions with logical operators && and || evaluate left to right:
C99, Section 6.5.14-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.
Since x++ is not zero, the expression short-circuits evaluation of everything to the right of ||, including their side effects. That's why only x++ is evaluated, so x becomes 2. The remaining variables stay at 1, as they should.
There's no sequence point in the expression:
z = ++x || ++y && ++z;
between the pre-increment of z and assignment to z.
So, if the ++z is actually evaluated, that puts you instantly into undefined behaviour territory and anything can happen. You are not permitted to modify the same object twice without an intervening sequence point. Annex C (from C99) lists all the sequence points and the controlling one here is following a full-expression (the entire calculation and assignment).
6.5 Expressions /2 states:
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.
However, given your initial value of x as 1, the ++z part of the expression is not evaluated, in this particular case. That doesn't make the expression itself any less dangerous since it will invoke UB in the case where the starting point is x == -1 and y != -1.
In this case, the controlling part of the standard is 6.5.14 Logical OR operator /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.
So, the ++x is evaluated first and, because it evaluates to not-zero, ++y && ++z is never evaluated. x is incremented to 2 and z is set to the "truthy" value of that, or 1, y remains untouched at 1.
This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 9 years ago.
In C have the following:
return (abc(1) || abc(2));
If abc(1 == 1) returns true will then call abc(2)?
No, it won't. This is called "short-circuiting" and it is a common flow-control mechanism:
With a && b, b is only evaluated if a is true; if a is false, the whole expression must necessarily be false.
With a || b, b is only evaluated if a is false; if a is false, the whole expression may still be true.
No. It's guaranteed (by The Standard), that if abc(1) returns true, abc(2) will NOT be called.
If abc(1) returns false, that it's guaranteed, that abc(2) WILL be called.
It's similar with &&: if you have abc(1) && abc(2), abc(2) will be called ONLY IF abc(1) return true and will NOT be called, if abc(1) return false.
The idea behind this is:
true OR whatever -> true
false OR whatever -> whatever
false AND whatever -> false
true AND whatever -> whatever
This comes from the boolean algebra
If abc(1==1) returns true will then call abc(2) ?
No, it won't. This behavior is known as short-circuiting. It is guaranteed by C and C++ standards.
C11(n1570), § 6.5.13 Logical AND operator
Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of
the first and second operands. If the first operand compares equal to 0, the second operand is not evaluated.
(Emphasis is mine.)
The same applies to the || operator.
abc(2) will be called only if abc(1) is false
According to C99 specification, logical OR operator says
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.
|| (logical comparison) breaks further checking, while | (bitwise comparison) doesn't.
You might also read: Difference between | and || or & and && for comparison
nop, the second abc(2) is called only if the left statement is false
In C, the logical || operator is tested from left-to-right, guaranteed. For the whole statement to be true, either condition can be true. So || keeps going from left to right until one condition is true, and then stops (or it gets to the end). So no, if abc(1) returns true then abc(2) will not be called.
Contrast with &&, which keeps going from left to right until one condition is false (or it gets to the end).
No. This is actually non trivial and defined in standard that logical operators are evaluated from left to right. Evaluation is stopped when the value can be determined with out further evaluation of operands. At least I am 100% sure for AND and OR.
This is non trivial problem, because therefore the evaluation of operands cannot be implicitly parallelized or optimized by reorganization of order, as the expected outcome could differ.
E.g. run-time troubles in wide-use cases such as if (*ptr && (ptr->number > other_number) )