Logical operators' precedence in C [duplicate] - c

This question already has answers here:
Precedence of && over || [duplicate]
(4 answers)
Closed 4 years ago.
#include <stdio.h>
int main(void) {
int a = 0, b = 0, c = 0;
++a || ++b && ++c;
printf("%d %d %d", a, b, c);
return 0;
}
The outputs are 1, 0, 0 by gcc 8.1.0. The &&‘s precedence should higher than ||.
Why are the b and c are still 0?

The expression ++a || ++b && ++c is grouped as ++a || (++b && ++c). But, the right hand side of || is only evaluated if ++a is 0, which it isn't.

There are three issues here:
Order of precedence.
Order of evaluation.
Short circuiting of logical operators.
Order of precedence implies that ++a || ++b && ++c is evaluated as ++a || (++b && ++c).
However, due to the short circuiting requirements of logical operators, ++a is evaluated first. Only if that evaluates to false will (++b && ++c) be evaluated. In your case, ++a evaluates to true. Hence, (++b && ++c) is never evaluated.

The logical OR operator || (as well as the logical AND operator &&) is one of the few operators that perform short circut operation.
Section 6.5.14 of the C standard says the following about the logical OR operator:
4 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.
Because ++a evaluates to 1, the result of the || operator is guaranteed to be 1 and the right hand side is not evaluated. Also, because && has higher precedence than ||, the right side of the || operator is ++b && ++c, meaning that neither ++b or ++c is evaluated.

Precedence only controls how expressions are parsed, not how they are evaluated. Arithmetic * has higher precedence than +, so a * b + c is parsed as (a * b) + c. However, each of a, b, and c may be evaluated in any order. The result of a * b must be known before it can be added to the result of c, but that doesn't mean that a * b must be evaluated before c.
Secondly, unlike most operators in C, the || and && operators force left-to-right evaluation. An expression like a || b && c will be parsed as a || (b && c), but a will always be evaluated first, and b && c will only be evaluated if the result of a is 0.

As far as precedence goes, x || y && z acts just like x + y * z: the second operator binds more tightly than the first one, and those expressions are equivalent to x || (y && z) and x + (y * z), respectively.
The reason that b and c in the question aren't incremented is because, in addition to precedence, logical operations short circuit: once you've gotten far enough along to know the result, the rest of the expression is skipped. Both || and && evaluate their arguments left-to-right, so in a() || b() and in a() && b(), the call to a() occurs before the call to b().
In simple cases, if a() returns true, then in the expression a() || b() the call to b() will not be executed, because it won't affect the result. Similarly, if a() returns false, then in the expression a() && b(), the call to b() will not be executed.
In the code in the example, the increments to b and c won't be performed, because ++a produces a non-zero value, so the result of the expression is true without needing to evaluate anything after ++a.

Operator precedence has nothing to do with order of evaluation. Precedence is the priority for grouping different types of operators with their operands.
So, the expression
++a || ++b && ++c;
will be evaluated as
++a || (++b && ++c);
Logical AND and Logical OR operator constitute sequence points and therefore guarantee a particular order of evaluation for their operands which is left to right.
Order of evaluation:
Ordering
......
If a sequence point is present between the subexpressions E1 and E2,
then both value computation and side effects of E1 are
sequenced-before every value computation and side effect of E2
Rules
.....
2) There is a sequence point after evaluation of the first (left) operand and before evaluation of the second (right) operand of the following binary operators: && (logical AND), || (logical OR), and , (comma).
Logical OR operation (expr1 || expr2) employs short-circuiting behavior. That is, expr2 is not evaluated if expr1 is logical 1 (true).
The initial value of a, b and c is 0. In the expression:
++a || ++b && ++c;
++a -> pre-increment a.
That means, the value of the expression ++a is resulting incremented value of a which will be 1. Since, || operator employs short-circuit behavior, the right hand side expression of || will not be evaluated. Hence, you are getting output - 1 0 0.
For better understanding, just try to change the ++a -> a++ in the expression.
The post increment operator also increase the value of operand by 1 but the value of the expression is the operand's original value prior to the increment operation. So, a++ will be evaluated to 0 and because of short-circuit behavior the right hand side expression of || operator (++b && ++c) will be evaluated.
The logical AND operation (expr1 && expr2) also employs short-circuiting behavior. With logical short-circuiting, the second operand, expr2, is evaluated only when the result is not fully determined by the first operand, expr1. That is, expr2 will be evaluated only if expr1 is logical 1 (true) and ++b will result in 1. So, if you do
a++ || ++b && ++c;
^^^
The output would be - 1 1 1.

Related

Logical AND OR and increment precedence [duplicate]

This question already has answers here:
What is short-circuit evaluation in C?
(3 answers)
Closed 2 years ago.
I want to ask a question about the code below.
int a=1, b=3, c=1;
if((a||c--)&&(c&&b--)) printf("%d",b);
printf("%d %d %d",a,b,c);
Why does the code prints "21 2 1" rather than "1 2 0" ?
Thanks for your help.
Since the or is evaluated to true immediately in (a||c--), the c-- is never evaluated. The compiler does this. If a statement is true right off the bat, it won't bother evaluating the rest. So, c is never decremented as the right side of the or is never evaluated.
Both || and && force left-to-right evaluation - the LHS is evaluated first and all side effects applied, then based on the result the RHS is evaluated.
Both operators short-circuit:
for a || b, if a is non-zero, then the result of the expression is 1 regardless of the value of b, so b is not evaluated;
for a && b, if a is zero, then the result of the expression is 0 regardless of the value of b, so b is not evaluated.
&& has higher precedence than ||, so a || b && c is parsed as a || (b && c).
Putting all that together, (a||c--)&&(c&&b--) is evaluated as follows:
a || c-- is evaluated as follows:
a is evaluated - its result is 1, so
c-- is not evaluated; because of this c's value is not changed, and
the result of the expression is 1
c && b-- is evaluated as follows:
c is evaluated - its result is 1, so
b-- is evaluated - its result is 3; as a side effect b is decremented, and
the result of the expression is 1
both a || c-- and c && b-- evaluate to 1
The values of a and c are unchanged (1 and 1, respectively), while b has been decremented and its value is now 2.
You can imagine this if statement
if((a||c--)&&(c&&b--)) printf("%d",b);
the following way
if ( a )
{
if ( c )
{
if ( b-- )
{
printf("%d",b);
}
}
}
else if ( c-- )
{
if ( c )
{
if ( b-- )
{
printf("%d",b);
}
}
}
So if the expression in the first if statement
if ( a )
evaluates to the logical true then this if statement
else if ( c-- )
never gets the control.
From the C Standard (6.5.14 Logical OR operator)
4 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.

Using logical operators on integers in C

Logical OR and Logical AND operator on integers in C
Can you explain me why the values of a,b,c are 11,10,1 respectively.
Why the value of b remains same as 10?
#include <stdio.h>
int main()
{
int a,b,c;
a=b=c=10;
c = a++ || ++b && ++c;
printf("%d %d %d",a,b,c);
return 0;
}
First, let's look at the order of operations. The logical AND operator && has higher precedence than the logcial OR operator ||, so the expression parses as follows:
c = a++ || (++b && ++c);
Next, both || and && are short circut operators. This means that the left has side is evaluated first, and if the result can be determined solely from that then the right hand side is not evaluated.
So a starts out with the value 10. a++ evaluates to the current value (10) while incrementing a as a side effect. This means the value 10 is the left hand side of ||. Because this is a non-zero value, the value of the entire expression is 1 and the right hand side ++b && ++c is not evaluated. Then this result is assigned to 1.
So the end result is a is incremented to 11, c is assigned 1 because that is the value of the || expression, and b is unchanged.
This expression
c = a++ || ++b && ++c;
can be equivalently rewritten like
c = ( a++ ) || ( ++b && ++c );
As the expression a++ is not equal to 0 then the second sub-expression ( ++b && ++c ) is not evaluated.
The value of the logical operator || and && is either 1 (true) or 0.
From the C Standard (6.5.14 Logical OR operator)
3 The || operator shall yield 1 if either of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
and
4 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.
So c gets the value 1 and a was increased.
Expanding, a little bit, on the other answers, you have to understand what your statement is actually doing.
a=b=c=10;
c = a++ || ++b && ++c;
The logical operators take, naturally, boolean operands, so your statement is (implicitly):
c = ( a++ != 0 ) || ( ++b != 0 ) && ( ++c != 0 );
Note, interestingly, that the order of precedence places the AND operator higher than the OR operator - which implies that ++b should be executed.
However, given the short-circuit operation of logical-OR, the first term is known to be true therefore c = 1 (ie true).
--
Regular readers will, of course, expect me to add a MISRA slant to my answer...
MISRA C:2012 Rule 13.5 covers this exact scenario... it states that The right hand operand of a logical && or || operator shall not contain persistent side effects
So a MISRA Compliant version of your code would be:
a=b=c=10;
a++;
b++;
c++; // This is actually *dead code*
c = a || ( b && c );
printf("%d %d %d",a,b,c);

C bitwise precedence and associativity

#include <stdio.h>
int main() {
int a = 1;
int b = a || (a | a) && a++;
printf("%d %d\n", a, b);
return 0;
}
when I ran this code the results were 1 and 1.
According to the C language Operator Precedence the operation && is supposed to happen before the operation ||. So shouldn't the result be 2 1 ? (a = 2, b = 1)
when OR'ing expressions in C, a shortcut is taken, I.E. as soon as an expression is evaluated to TRUE, the rest of the OR'd expressions are not evaluated
The first expression a evaluates to TRUE, so all the rest of the expressions are not evaluated, so a is never incremented
When applying the operator precedence rules, the expression is equivalent to:
int b = a || ((a | a) && a++);
The evaluation or the operands to || and && is performed from left to right and shortcut evaluation prevents evaluating the right operand if the left operand can determine the result: since a is non zero, a || anything evaluates to 1 without evaluating the right operand, hence bypassing the a++ side effect.
Therefore both a and b have value 1 and the program prints 1 1.
Conversely, if you had written int b = (a || ((a | a)) && a++;, the left operand of && would have value 1, so the right operand need to be evaluated. a++ evaluates to 1 but increments a, so b have final value 1 and a is set to 2, producing your expected result.
The confusion comes from equating operator precedence with order of evaluation. These are two separate notions: operator precedence determines the order in which to apply the operators, but does not determine the order of evaluation of their operands.
Only four operators have a specified order of evaluation of their operands: &&, ||, ? : and , and the first 2 may skip evaluation of one, depending on the value of the other operand and the third only evaluates the first and only one among the second and third operands. For other operators, the order of evaluation of the operands is unspecified, and it may differ from one compiler to another, one expression to another or even one run to another, although unlikely.
When I try to put a || (a | a) into a parenthesis. The result was as you expected.
So I guess that when C compiler executes an OR operator and it get a True value to the OR, the execution will finish immediately.
In your case, when the compiler executed the a || (a | a) (1 || something) operation. Value of b will be declared to 1 right away and a++ operator won't be execute.

Why pre increment is not evaluated [duplicate]

This question already has answers here:
Is short-circuiting logical operators mandated? And evaluation order?
(7 answers)
Closed 5 years ago.
#include <stdio.h>
int main(){
int a=5,b=-7,c=0,d;
d=++a && ++b || ++c;
printf("%d %d %d %d",a,b,c,d);
}
Here value of c should increase to 1 but it is giving 0, why?
It's because of short-circuiting. If you have a && b, then b will only be evaluated if a is true. Similarly, if you have a || b, then b will only be evaluated if a is false.
In your case, ++a && ++b || ++c groups as (++a && ++b) || ++c. First ++a is evaluated, and it's true, so ++b is evaluated, and it's also true. At this point, evaluation stops because it is now certain that the result of the || operator is true, so ++c is never evaluated.
Because the || doesn't evaluate the right hand side if the left hand side evaluated to true. In your example,
++a && ++b
evaluates to non-zero, which is treated as a true. Therefore, according to the rules of lazy evaluation, the ++c is completely ignored.

An example about operator precedences

As far as I'm aware of, unary operators have prior precedence over || and &&. In the following code, I'd expect an output where all outputs are equal to 1. Yes, there is a short-circuit but shouldn't those pre-increments calculated before || and &&? How these precedences work here?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0, b = 0, c = 0;
a = b = c == 1;
c = ++a || ++b && ++c; // short-circuit here
printf("a=%d, b=%d, c=%d\n", a, b, c);
}
Output:
a=1 b=0 c=1
Operator precedence doesn't have any relation with order of evaluation. Higher precedence means that grouping of operands to that operator is done first.
In the statement
c = ++a || ++b && ++c;
the grouping/binding of the operands of ++ will be done first and then that of && and || respectively. To show this I am adding parenthesis to the expression
++ has higher precedence so bind operand to it first
c = (++a) || (++b) && (++c);
&& has higher precedence than ||
c = (++a) || ((++b) && (++c));
|| has higher precedence than =
c = ((++a) || ((++b) && (++c)));
= has least precedence of all
(c = ((++a) || ((++b) && (++c))));
The fact that || is short-circuiting and the lowest precedence operator explains the result. Because ++ is the higher precedence than && and && is higher precedence than ||, the expression tree for ++a || ++b && ++c is:
|| -- left: ++a
-- right: && --left: ++b
--right: ++c
So, to evaluate the expression, C first considers the rules for evaluating ||, given by 6.5.14 in the C11 standard. Specifically:
6.5.14.4: 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.
The fact that || is short-circuiting means that it evaluates its left operand first and only evaluates its right operand if the left is zero. So to evaluate the expression ++a || ++b && ++c, C requires the following:
Evaluate ++a (a is incremented by one and the expression is equal to its incremented value). If it is non-zero, then || expression is equal to 1 and the right side is never evaluated.
Otherwise, evaluate ++b and ++c, in left-to-right order. If ++b is zero, then ++c is never evaluated. If both are non-zero, then the expression is equal to 1.
Because ++a evaluates to 1, the right side of the || is never evaluated. This is why you have a==1, b==0, and c==1.
There's one additional problem with the statement c = ++a || ++b && ++c, which is that there's a potential for the statement to invoke undefined behavior. If ++a is false and ++b is true, then ++c has to be evaluated. However, there is no sequence point between c = ... and ++c. Since the expressions both modify c with no sequence point in between, the behavior is undefined. For a further explanation of this see, for example, https://stackoverflow.com/a/3575375/1430833
I think you're confusing operator precedence with order of evaluation. Here's an outline of what happens. In the comments, my use of = is that of identity - much like the mathematical equals sign.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// all variables are assigned the value 0
int a = 0, b = 0, c = 0;
// a and b are equal to the evaluation of `c == 1`, which is false. a and b are 0
a = b = c == 1;
/*
&& has higher precedence than ||, so ++b and ++c are "grouped": ++a || (++b && ++c)
++a is evaluated, a = 0+1 = 1. 1 is true, short circuit the second grouping.
c = a = 1.
*/
c = ++a || ++b && ++c; // short-circuit here
// a = c = 1, b = 0
printf("a=%d, b=%d, c=%d\n", a, b, c);
}

Resources