C bitwise precedence and associativity - c

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

Related

condition check in If statement [duplicate]

I'm studying C from A Book on C by Kelley-Pohl, and there's this exercise that I don't understand:
int a = 0, b = 0, x;
x = 0 && (a = b = 777);
printf("%d %d %d\n", a, b, x);
x = 777 || (a = ++b);
printf("%d %d %d\n", a, b, x);
They just say to imagine the output and compare it to the real one. I thought the output would have been
777 777 0
778 778 1
but it is
0 0 0
0 0 1
From the C Standard (6.5.13 Logical AND operator)
3 The && operator shall yield 1 if both of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
and
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.
In this expression statement
x = 0 && (a = b = 777);
the first operand compares equal to 0. So the second operand is not evaluated that is the values of the variables a and b are not changed. So the variable x will be set to 0 according to the paragraph #3 of the section.
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.
In this expression statement
x = 777 || (a = ++b);
the first operand compares unequal to 0. So the second operand is not evaluated that is the values of the variables a and b are not changed.. So the variable x will be set to 1 according to the paragraph #3 of the section.
If you will change the order of the operands in the expressions like
x = (a = b = 777) && 0;
x = (a = ++b) || 777;
you get the expected by you result.
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.
Another trap in this expression is that; the precendence of the operators. Such as &&, || (logical and, logical or) operators have higher precedence to the assignment operator(=).
in this case x=(0&&(a=b=777)) is same as x=0&&(a=b=777), however x=(0&(a=b=777)) is more readable than the previous one.
Logical operators select one of their operands and returns the result accordingly.
They also force their operands to be boolean as true or false.
In this expression "x=0&&(a=b=777)" since the first operand is false the result will be equal to first operand.Second operand is short circuited and will not be executed.So the output will be a=b=0, x=0.
x=777 || (a=++b) in this expression since the first operand is true the result will be equal to the first operand and logical operator will not check the second operand, logical OR operator will bypass the second operand.In this expression since the first operand is true (777 is converted to true) the result will be True means x=1.Since the second operand is skipped "a" and "b" values will remain same as their previous values, in this case 0,0

Incrementation issues [duplicate]

I'm studying C from A Book on C by Kelley-Pohl, and there's this exercise that I don't understand:
int a = 0, b = 0, x;
x = 0 && (a = b = 777);
printf("%d %d %d\n", a, b, x);
x = 777 || (a = ++b);
printf("%d %d %d\n", a, b, x);
They just say to imagine the output and compare it to the real one. I thought the output would have been
777 777 0
778 778 1
but it is
0 0 0
0 0 1
From the C Standard (6.5.13 Logical AND operator)
3 The && operator shall yield 1 if both of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
and
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.
In this expression statement
x = 0 && (a = b = 777);
the first operand compares equal to 0. So the second operand is not evaluated that is the values of the variables a and b are not changed. So the variable x will be set to 0 according to the paragraph #3 of the section.
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.
In this expression statement
x = 777 || (a = ++b);
the first operand compares unequal to 0. So the second operand is not evaluated that is the values of the variables a and b are not changed.. So the variable x will be set to 1 according to the paragraph #3 of the section.
If you will change the order of the operands in the expressions like
x = (a = b = 777) && 0;
x = (a = ++b) || 777;
you get the expected by you result.
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.
Another trap in this expression is that; the precendence of the operators. Such as &&, || (logical and, logical or) operators have higher precedence to the assignment operator(=).
in this case x=(0&&(a=b=777)) is same as x=0&&(a=b=777), however x=(0&(a=b=777)) is more readable than the previous one.
Logical operators select one of their operands and returns the result accordingly.
They also force their operands to be boolean as true or false.
In this expression "x=0&&(a=b=777)" since the first operand is false the result will be equal to first operand.Second operand is short circuited and will not be executed.So the output will be a=b=0, x=0.
x=777 || (a=++b) in this expression since the first operand is true the result will be equal to the first operand and logical operator will not check the second operand, logical OR operator will bypass the second operand.In this expression since the first operand is true (777 is converted to true) the result will be True means x=1.Since the second operand is skipped "a" and "b" values will remain same as their previous values, in this case 0,0

Logical operators' precedence in C [duplicate]

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.

What is short-circuit evaluation in C?

I'm studying C from A Book on C by Kelley-Pohl, and there's this exercise that I don't understand:
int a = 0, b = 0, x;
x = 0 && (a = b = 777);
printf("%d %d %d\n", a, b, x);
x = 777 || (a = ++b);
printf("%d %d %d\n", a, b, x);
They just say to imagine the output and compare it to the real one. I thought the output would have been
777 777 0
778 778 1
but it is
0 0 0
0 0 1
From the C Standard (6.5.13 Logical AND operator)
3 The && operator shall yield 1 if both of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
and
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.
In this expression statement
x = 0 && (a = b = 777);
the first operand compares equal to 0. So the second operand is not evaluated that is the values of the variables a and b are not changed. So the variable x will be set to 0 according to the paragraph #3 of the section.
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.
In this expression statement
x = 777 || (a = ++b);
the first operand compares unequal to 0. So the second operand is not evaluated that is the values of the variables a and b are not changed.. So the variable x will be set to 1 according to the paragraph #3 of the section.
If you will change the order of the operands in the expressions like
x = (a = b = 777) && 0;
x = (a = ++b) || 777;
you get the expected by you result.
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.
Another trap in this expression is that; the precendence of the operators. Such as &&, || (logical and, logical or) operators have higher precedence to the assignment operator(=).
in this case x=(0&&(a=b=777)) is same as x=0&&(a=b=777), however x=(0&(a=b=777)) is more readable than the previous one.
Logical operators select one of their operands and returns the result accordingly.
They also force their operands to be boolean as true or false.
In this expression "x=0&&(a=b=777)" since the first operand is false the result will be equal to first operand.Second operand is short circuited and will not be executed.So the output will be a=b=0, x=0.
x=777 || (a=++b) in this expression since the first operand is true the result will be equal to the first operand and logical operator will not check the second operand, logical OR operator will bypass the second operand.In this expression since the first operand is true (777 is converted to true) the result will be True means x=1.Since the second operand is skipped "a" and "b" values will remain same as their previous values, in this case 0,0

Explanation for this function's output

I am doing review questions which ask me "What is the output of the following," and I am having some trouble understanding something about this function:
int a = 1, b = 1, c = -1;
c = --a && b++;
printf("%d %d %d", a, b, c);
The output is 010. My question is about line 2, c = --a && b++. How is this line processed, and how does it work/change the values? And if it were c = --a || b++? From my understanding I thought the output would be 020.
The key concept to understanding the result is short-circuit evaluation of Boolean operators (&& and ||) -- if, after evaluating the left-hand side of a Boolean operator, the value of the right-hand side cannot affect the overall result, then it will not be evaluated and any side-effects it would produce will not happen.
In the first case, since --a evaluates to 0 (=false) the second part of ... && ... is not evaluated, since "false AND anything" will always be false. Specifically, b++ is never executed, and so its value remains 1 in the output.
In the case of --a || b++, the value of the whole expression cannot be determined by the left-hand side ("false OR something" can still be true) so the b++ is evaluated (and it's side-effect, incrementing b, happens).
The other concept needed to fully understand the results is the difference between pre- and post-increment/decrement operators. If the -- or ++ appears before the variable (as in --a) then the variable is decremented or incremented first and new value is used to evaluate the whole expression. If the -- or ++ appears after the variable (as in b++) then the current value of the variable is used to evaluate the expression and the increment/decrement happens after this has happened.
It should be noted that expressions that try to combine two or more instances of --/++ of the same variable (e.g. a++ + ++a) are quite likely to invoke undefined behaviour -- the result may vary by platform, compiler, compiler and even the time of day.
In the expression c = --a && b++, a gets decreased and returned. Now the second argument of the expression --a && b++ is not evaluated because of short circuit evaluation---once we see that --a==0 we already know that the expression will be 0 regardless of what is the other argument---, so b remains unchanged.
Decreased a is 0 and b remains 1.
The output is, as you suggest, 0 1 0.
Regarding the second question, if you write c = --a || b++, the variable a again goes to zero but the expression can still evaluate to true---we must thus evaluate the second part as well, thus executing b++ which returns 1 and increases b. In this case the output would be 0 2 1, because c is assigned the value of 0 || 1 which is 1.
In short, read up on
pre- and post-increment in C and C++ and on
short circuit evaluation.
The thing you need to focus on here first is the properties of prefix and postfix operators and their differences.
For Postfix increment and decrement operators, C11, chapter §6.5.2.4, (emphasis mine)
The result of the postfix ++ operator is the value of the operand. As a side effect, the
value of the operand object is incremented [...] The postfix -- operator is analogous to the postfix ++ operator, except that the value of
the operand is decremented.
For Prefix increment and decrement operators, C11, chapter §6.5.3.1, (emphasis mine)
The value of the operand of the prefix ++ operator is incremented. The result is the new
value of the operand after incrementation. [...] The prefix -- operator is analogous to the prefix ++ operator, except that the value of the
operand is decremented.
Now, there comes the property of the Logical AND (&&) operator. From chapter §6.5.13, (again, emphasis mine)
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, in your case,
int a = 1, b = 1, c = -1;
c = --a && b++;
gets evaluated as
c = 0 && .....; // done..., a is decremented to 0,
// so, LHS of && is 0, RHS is not evaluated,
// b remains 1
// and finally, C gets 0.
On the other hand, if logical OR (||) would have been used, then, as per the property, mentioned in chapter §6.5.14
[...] 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, for the case
int a = 1, b = 1, c = -1;
c = --a || b++;
it will be evaluated as
c = 0 || 1; //yes, b's value will be used, and then incremented.
So,
printf("%d %d %d", a, b, c);
will be
0 2 1
b++ is simply never executed because --a evaluates to false in an and condition.
The right side of the and is never executed because not needed. Hence b is never incremented and hence the output you did not expect.
c = --a && b++;
In this first --a is evaulated and a becomes 0 , as soon as 1 operand of && is false , b++ is not evaluated , therefore ,b remains 1 and c becomes 0.
The line :
c = --a && b++;
decreases a to 0, so the statement 0 && anything else results to 0. This is why a and c result to 0, as it seems you have understood.
Now let's see the part you don't get. When a is evaluated to 0, the right part of && does not need to be evaluated, as no matter what the value of the right part will be calculated to be, the result will be 0. This means that b++ will not be evaluated and therefore b will retain its initial value. This is why you see the value 1 instead of 2, and consequently the output 0 1 0 instead of 0 2 0.
--a : mean you decrease a before do the line. b++: increase b after do the line. so that c ( at that time ) = 0+1 =1; then: a =0, b = 2, c =1; OK

Resources