A specific short-circuiting example in C - c

I understand the basic concept of short-circuiting with operators, but why does
int i = 0, j = -1, k = 1, m;
m = !(i++ && ++j) || ++k;
printf("%d %d %d %d", i, j, k, m);
have 1 -1 1 1 as an output? Specifically, why is j == -1 instead of 0?
I know similar questions have been already asked, but I don't understand this specific example which I didn't find anywhere.

i = -1;
i++; // value of expression is -1
// side effect is changing i to 0
if (i++) ; // value of `i++` is zero; the if will not "trigger"
i = 0;
if (i++ && foo) ; // i++ has value of zero (false)
// so false && <anything> is false
// so foo is not evaluated

int i = 0, j = -1, k = 1, m;
!(i++ && ++j) || ++k; ==> only i++ will be evaluated, j and k will not be evaluated
lets just say we are substituting the values of variables, then the expression becomes as below.
!(0 && ++ -1) || ++1
step 1:
!(0 && ++ -1) ==> for && operator if left side operand is False then we dont need to check for right side operand, so -1 wont be incremented, so value of j will be -1 itself.
and hence the left side expression before || becomes !(0)
step 2:
!(0) || ++1
now !(0) will be 1 , so for || operator if left side operand is TRUE , then no need to go for right side operand, then ++k will not be executed.
m = 1 || ++1 ==> 1
since only i++ is evaluated , it will change its value to 1
so the out put is : 1 -1 1 1

The value of the postfix increment operator is the value of its operand before incrementing.
So the value of the expression i++ is equal to 0 because the variable i was initialized by 0.
So as the value of the sub-expression i++ is 0 then the sub-expression ++j in this expression
(i++ && ++j)
is not evaluated and the value of the expression itself is 0.
Applying the negation operator
!(i++ && ++j)
you will get 1 (logical true). So the sub-expression ++k of the expression
!(i++ && ++j) || ++k
will not be evaluated.
As a result the value of the whole expression is equal to 1 that is assigned to the variable m.
m = !(i++ && ++j) || ++k;
On the other hand as it was pointed out in the beginning the expression i++ was evaluated. So after this statement i will be equal to 1.

Related

why does the value of num2 in below expression becomes -1 instead of 0?

The below C program gives output -1 for num2. I do not understand why. Can somebody help me with it?
#include <stdio.h>
int main(void)
{
int num1 = 0, num2 = -1, num3 = -2, num4 = 1, ans;
ans = num1++ && num2++ || ++num4 && num3++;
printf("%d %d %d %d %d", num1, num2, num3, num4, ans);
return 0;
}
output:
1 -1 -1 2 1
The expression num1++ && num2++ || ++num4 && num3++ is parsed as:
(num1++ && num2++) || (++num4 && num3++)
Both || and && use shortcut evaluation, meaning that the right operand if and only if the left operand evaluates to false (resp. true).
num1++ && num2++ is evaluated first:
num1++ is evaluated: it evaluates to the initial value of num1, 0 and num1 is incremented.
since the left operand if false, the right operand of && is not evaluated (num2 is unchanged`) and the expression is false:
num1++ && num2++ is false, so the right operand of || must be evaluated to determine the value of the whole expression:
++num4 is evaluated: the value is 2 and num4 is incremented.
the left operand of this second && operator is true, so the right operand is evaluated
num3++ is evaluated: the value is -2 and num3 is incremented.
2 && -2 is true, the whole expression evaluates to true, which has type int and the value 1 in C: ans receives the value 1.
printf outputs 1 -1 -1 2 1 (without a trailing newline)
If the left side of a logical AND && is false, the right side will not be evaluated as the result can be determined as false already.

Finding logic for this output

Explain how this output comes.
#include <stdio.h>
int main()
{
int x,y,z;
x = y = z = -1;
z = ++x && ++y && ++z;
printf("%d %d %d", x, y ,z);
return 0;
}
I thought x,y,z all values will be 0 but the actual output is x=0,y=-1,z=0.
There are two things that are involved here: Operator associativity, and short-circuit evaluation (please see the link for a description of what it is and what it does).
Due to the associativity of the && operator, the expression ++x && ++y && ++z is equal to (++x && ++y) && ++z.
If we do the sub-expression ++x && ++y then the result is false. What happens is that ++x results in 0, so we have 0 && ++y. And in C zero is the same as boolean false, and due to the short-circuit evaluation ++y never happens. The value of y stays at -1.
So with the result of the first sub-expression, we have false && ++z. Again due to short-circuit evaluation ++z never happens, and the result is again false.
So the result of ++x && ++y && ++z is false, which is then assigned to z. And in the assignment the boolean false is implicitly converted to the integer value 0. Which is the printed value of z.
You have a incorrect declaration to start with, the last variable in the declaration should have been z instead of x back again (corrected since the last edit)
As for the result, you would see an output 0 -1 0, because after the first pre-increment, the value of x becomes 0 and the evaluation short-circuits ( operand right to && is not evaluated) as 0 && ++y producing integer 0 and pre-increment on y never happening at all. The expression now becomes 0 && (++z) which would short-circuit again to produce 0
The result of the final expression z when printed with %d specifier becomes 0.
From this link I can read
The ‘&&’ operator doesn’t evaluate second operand if first operand becomes zero.
z = ++x && ++y && ++z = ((++x && ++y) && ++z)
Inner parenthesis (++x && ++y)
++x = -1 + 1 = 0 second operand ++y is not evaluated, y = -1, z = -1
Outer parenthesis
((++x && ++y) && ++z) = (0 && ++z)
Again ++z is not evaluated z remains -1
++x && ++y && ++z = 0 and x = 0, y = -1, z = -1
Then you overwrite the value of z by assigning ++x && ++y && ++z = 0 to z
so the old value of z namely -1 is replaced by ++x && ++y && ++z namely 0
Finally
x = 0, y = -1, z = 0

Problems containing multiple "or" operators in C

I was solving some problems related to "or" operators in C.
The body of the program was like what mentioned below:
#include<stdio.h>
main() {
int i = 4, j = -1, k = 0, w, x, y, z;
w = i || j || k ;
x = i && j && k ;
z = i && j || k ;
printf("\n w=%d , x = %d", w, x);
printf("\n y=%d , z = %d", y, z);
}
Can someone please tell me the mechanism of these statements?
These are binary operators, they take two arguments. When confronted with a more complicated expression you can break it down into sets of binary operations.
For example, z = i && j || k; could be written as z = ( (i && j) || k ). Or in pictorial form:
z
=
||
/ \
&& k
/ \
i j
To know that the tree has this layout we look up operator precedence (or language grammar rules), the rule is that to choose between && and ||, the || is the 'outer' operation (i.e. lower precedence).
These operators also do short-circuiting, although that is not relevant in this particular example.
So, looking at the above table, i && j gives 1 because both i and j are non-zero. The 1 || k gives 1 because at least one of the operands is non-zero. Finaly 1 is assigned to z.
You can find the right values for w and x in a similar way, using the precedence rule that the left-most && is the inner one, when the situation is a && b && c, and similarly for ||.
the || and && operators are logical operators, which means they evaluate the numbers as either 'true' or 'false'
In that sense, i and j are 'true' and k is 'false'. So, calculating the outcome:
w = 'true' or 'true' or 'false' = true = 1
x = 'true' and 'true' and 'false' = false = 0
z = 'true' and 'true' or 'false' = true = 1
y isn't defined and will contain 0 or garbage
--edit--
note that && and || are left to right operators, therefore the first operator is always evaluated first.

Short circuit behavior of logical expressions in C in this example

PROGRAM
#include <stdio.h>
int main(void)
{
int i, j, k;
i = 1; j = 1; k = 1;
printf("%d ", ++i || ++j && ++k);
printf("%d %d %d", i, j, k);
return 0;
}
OUTCOME
1 2 1 1
I was expecting 1 1 2 2. Why? Because the && has precedence over ||. So I followed these steps:
1) j added 1, so j now values 2...
2) k added 1, so k now values 2...
3) 2 && 2, evaluates to 1...
4) No need of further evaluation as the right operand of || is true, so the whole expression must be true because of short circuit behavior of logical expressions...
Why am I wrong?
Precedence affects only the grouping. && has a higher precedence than || means:
++i || ++j && ++k
is equivalent to:
++i || (++j && ++k)
But that doesn't mean ++j && ++k is evaluated first. It's still evaluated left to right, and according to the short circuit rule of ||, ++i is true, so ++j && ++k is never evaluated.

is the precedence of operator ignored in 'if' conditions

I'v a following code:
void main()
{
int k, x, y, z;
printf("\nExperiment 1:");
x = 0, y = 0, z = 0;
k = x++ || y++ && z++;
printf("\nx = %d, y = %d, z = %d and k = %d\n", x, y, z, k);
printf("\nExperiment 2:");
x = 1, y = 0, z = 0;
k = x++ || y++ && z++;
printf("\nx = %d, y = %d, z = %d and k = %d\n", x, y, z, k);
}
The output:
Experiment 1:
x = 1, y = 1, z = 0 and k = 0
Experiment 2:
x = 2, y = 0, z = 0 and k = 1
What I've understood is:
For the expression to be true, either left side or right side of '||' has to be non-zero. It starts from left. If left is non-zero, it doesn't evaluate further. If it is zero, it starts on right side. On right we have '&&'. So, we again start from left side of && and in case it is zero, the expression cannot be true and it doesn't proceed. Otherwise it evaluates the right side of '&&'
My assumption was operator && has higher precedence. So, both of its arguments should have been evaluated and then && should have been applied over it followed by evaluation of both arguments of ||.
Is compiler optimizing itself? I've used Visual Studio TC compilar with Optimization disabled.
I think this is covered in C11 by §6.5.14 Logical OR operator (my emphasis)
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 the expression
k = x++ || y++ && z++;
is interpreted as (due to precendence rules):
k = x++ || (y++ && z++);
In Experiement 1, we have x = y = z = 0;.
In Experiement 2, we have x = 1, y = z = 0;.
So, the right-hand side expression stops after evaluating y++, since the value of that is 0 and thus the boolean and cannot become true.

Resources