Shortcircuiting of AND in case of increment / decrement operator - c

In the code below:
#include <stdio.h>
int main()
{
int a = 1;
int b = 1;
int c = a || --b;
int d = a-- && --b;
printf("a = %d, b = %d, c = %d, d = %d", a, b, c, d);
return 0;
}
i was expecting the output to be:
a=0,b=1,c=1,d=0
because due to short circuiting in the line below, ie a-- returns 0 so the other part wont get executed right?
int d = a-- && --b;
The output is:
a = 0, b = 0, c = 1, d = 0
can anyone please explain?

In first case
int c = a || --b;
After this a=1 , b=1 and c=1
a value is 1 , because of short circuit evaluation --b did not performed
int d = a-- && --b;
a-- is post decrement so decrement of a won't effect in expression
where as --b is pre decrement so effects here
Your condition becomes
int d= 1 && 0 ;
After this a=0; , b=0,c=1 and d=0.

int c = a || --b;
In this line, the C standard requires the C implementation to evaluate a first and, if it is not zero, not to evaluate --b. Although -- has higher precedence than ||, that just means that -- is grouped with b for the purposes of determining the structure of the expression, not for purposes of evaluating it. The left side of an || operator must be evaluated before the right side and, if the left side is true, the right side must not be evaluated, even in part.
So, after the above, b is not changed; it is still 1.
int d = a-- && --b;
As with ||, the left-hand side of the && is evaluated first. So a-- is evaluated. This changes a to 0. However, the value of a-- is a before the change, so it is 1. A value of 0 would prevent the right side from being evaluated (because, once we know the left side is zero, we know the value of the complete && expression is zero). But, since the left side is not zero, --b must be evaluated to finish the &&. This changes b to 0. “Short-circuiting” means the left side is evaluated first, but the right side is still evaluated when necessary.

In the first or operation, --b is not executed since a equals 1:
int c = a || --b;
But b is decremented here:
int d = a-- && --b;
Because a equals 1 and is decremented after it is evaluated (a-- equals 1). In other words, this line is similar to:
int d = 1 && --b;
b was equal to 1 so now b equals 0 now. And d also equals 0 because --b returns 0.

the line below, ie a-- returns 0
No, it doesn't. It yields 1, as the post-decrement operator evaluates to the unmodified value of the variable. What you are thinking about is perhaps --a.

c = a || --b
so at first a is evaluated and a value is 1 which is true. So compiler does not evaluate --b. So b value is still 1
Now
d = a-- && --b
a-- && --b => 1 && 0 (since --b = 0 ) since b value is at 1.
why 1 because a-- is post decrement operator
Why 0 because --b is pre decrement operator
so 1 && 0 returns 0 and this value is stored in d
So the output: a = 0, b = 0, c = 1, d = 0

You're mixing up a-- with --a. The result of the expression a-- is a before the decrement, while --a is a after the decrement; in other words:
int a = 1;
int b = a--; // b == a == 1
int c = --b; // c == b-1 == 0
As a result, you have:
int d = a-- && --b;
// => 1 && b-1
// => 1 && 0
// => 0

Related

Short-circuit evaluation evaluating if( (a = 4) || (b = 6) || (c = 7) || (d = 8) )

The program is posted below:
#include <stdio.h>
int main(void)
{
int a, b, c, d;
printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);
if( (a = 4) || (b = 6) || (c = 7) || (d = 8) )
printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);
}
I understand the first printf statement but in the 2nd if statement I do not understand what it would evaluate when there is only one equal sign instead of two.
The output is :
a = 0, b = 0, c = 32767, d = -341260496
a = 4, b = 0, c = 32767, d = -341260496
So the 2nd if statement ended up being true but how?
I thought one equal sign would be assigning a value to the variables.
I do not understand what if would evaluate when there is only one equal sign instead of two.
One equal sign makes it an assignment. Hence, a=4 evaluates to 4, which is interpreted as "true" by the logical "OR" operator ||. At this point no further evaluation is happening due to short-circuiting, so the remaining variables retain the values that they have prior to the if statement.
Note: Printing unassigned variables causes undefined behavior. You should change the declaration line as follows:
int a = 0, b = 0, c = 0, d = 0;
This call of printf
int a, b, c, d;
printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d);
has undefined behavior because variables a, b, c, and d are not initialized and have indeterminate values that can be trap values.
In the condition of the if statement
if( (a = 4) || (b = 6) || (c = 7) || (d = 8) )
there is assignment expression
a = 4
According to the C Standard (6.5.16 Assignment operators)
3 An assignment operator stores a value in the object designated by
the left operand. An assignment expression has the value of the left
operand after the assignment,111) but is not an lvalue...
And further (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.
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.
Thus only the assignment
a = 4
will be performed in this if statement
if( (a = 4) || (b = 6) || (c = 7) || (d = 8) )
all other variables still will be uninitialized.
As the value of the assignment that is 4 is not equal to 0 then the if sub-statement will be executed.
So the 2nd if statement ended up being true but how?
In C, assignments are also a sort of expression that evaluate to some value. The value is (in most situations) the right hand side of the assignment.
In this case, (a = 4) evaluates to 4, which is true in the world of C, thus short-circuiting the entire condition and skipping the assignments for b, c and d. Which is why only a is initialised while the others retain their junk values.
In short, when you compare using OR, evaluation is done until the 1st occurrence of TRUE. So only a=4 is assigned. Rest are still uninitialized.

Basic programming exercise about logical operators

I have a problem with a question in my book:
#include<stdio.h>
void main()
{
int a=5, b=-7, c=0, d;
d = ++a && ++b || ++c;
printf("\n%d%d%d%d",a,b,c,d);
}
The question asks me what is the output of the code. I ran it and the result on the screen is 6-601. I understand why a=6 and b=-6, but I don't understand why c=0 and d=1?
I believe you already got your answer, but just to elaborate a bit step-by-step, let me add one more clarification here. Firstly, to quote the properties of the && and || operators, from C11 standard, chapter §6.5.13 and §6.5.13, respectively,
(I)
The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it
yields 0. [...] If the first operand compares equal to 0, the second
operand is not evaluated.
and
(II)
The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it
yields 0. [...]. If the first operand compares unequal to 0, the second operand is
not evaluated.
and they both guarantee left-to-right evaluation. So, comparing your code,
d = ++a && ++b || ++c;
it happens like
d = ((++a && ++b) || ++c );
which evaluates to
d = (( 6 && ++b ) || ++c);
and then
d = ( ( 6 && (-6) ) || ++c);
Now in above stage, (I) is fulfilled and it comes down to
d = ( 1 || ++c);
Now, following the emphasis, which already meets the (II), so no further evaluation of the RHS operand of || is performed (i.e., ++c is not evaluated), and it appears to be d = 1 and the final result, 1, is stored into d.
That's how, a == 6, b == -6, c == 0 and d ==1.
Having said that, void main() should be changed to int main(void), at least to conform with the standard.
The || OR operator is short-circuiting, which means that if the left side is true then the right side is not evaluated. In this case ++a && ++b evaluates to true, so ++c is never run and c keeps its value of zero.
Also since it evaluates to true, this is denoted with 1 which is stored in d.
Any non-zero value is considered to be true and the result of boolean operations is defined to be 0 or 1 as an integer.

Why does the value of c not change?

#include <stdio.h>
void main()
{
int a = 5, b = -7, c = 0, d;
d = ++a && ++b || ++c;
printf("\n %d,%d,%d,%d", a, b, c, d);
}
In the above code, the output is 6,-6,0,1. Why is the value of c 0 and the value of d 1?
how did d get the value as 1?
That is because || first checks the left part and if it is true it return true without evaluating the right part.
In C any non zero is treated as True and zero as False
int a = 5, b = -7, c = 0, d;
d = ++a && ++b || ++c;
Here ++a and ++b are non zero and both are treated as True so ++a&&++b becomes True and the expression stops evaluating over there.
There are already good answers that explain why c is 0 after the line
d = ++a && ++b || ++c;
is executed.
The line is equivalent to:
d = (++a && ++b || ++c);
That explains why d is 1.
int a = 5, b = -7, c = 0, d;
d = ++a && ++b || ++c;
let's analyze the statement part by part
++a : a=6
++a && ++b: b becomes -6 ,and then it does : 6 && -6 ,which is equal to 1
now there is a || (or symbol) ,but this cannot affect the value of d since
1||"value2" =1 ,
so the compiler does not evaluate "++c" .
so c remains 0 and d becomes 6 && -6 =1
&& has higher precedence than || so first ++a&&++b is evaluated first and it becomes true. The expression becomes true || ++c and || will evaluate from left to right since || encounters true and it returns 1 to d without evaluating ++c. So c value will not be incremented
An evaluation tree is created which does the evaluation. The || part is parent and the two parts on its side are its parents. When it evaluates one child, if it gets true, it doesn't evaluate the other child.

Evaluation of logical operand

If I have the following:
int a = -10 && 0;
then does C evaluate -10 as 1 because -10 is different from 0 and then make
the comparation between 1 && 0 to get 0 as result?
Or does let -10 and make the comparation as written?
Instead if I write:
int c = 10;
int b = 11;
int res = c > 10 && b == 11;
then the C make this:
c > 10 is false so it evaluates to 0 while
b == 11 is true so it evaluates to 1
then the expression is:
0 && 1 with 0 as result.
The operator && and || has short circuit behavior1. In
int a = -10 && 0;
since left operand is -10, which is non-zero and hence true, therefore right operand, i.e 0 is checked. In
int res = c > 10 && b == 11;
since left operand is evaluated to false, right operand is not evaluated.
1 C11 6.5.13 (p4): If the first operand compares equal to 0, the second operand is not evaluated.
For
int a = -10&&0;
-10 is treated as higher logic(1). However, result still be 0.

OR and AND operation in C

I have a doubt in the program below.
int main()
{
int i = -3,j = 2, k = 0,m;
m = ++i || ++j && ++k;
printf("%d %d %d %d\n", i, j, k, m);
return 0;
}
I get the output as -2 2 0 1.
In OR operation if 1st value is true then it won't evaluate the 2nd one so i = -2 and j =2.
Then comes the AND operation . It will check for both the value to be true.So if k = 1 then m = 1.
So the output should be -2 2 1 1. I run and check and got output as -2 2 0 1 but I could not understand how.
You used a short circuit or. Since ++i evaluates to -2, which is not 0, it short circuits and doesn't evaluate the rest of the expression. As a result, neither j or k get incremented.
Also note that the short circuit operators, || and &&, are left associative and that || is higher precedence than &&. As a result, the || gets evaluated first, and early outs if the left hand side evaluates to true, while && early outs if the left hand side evaluates to false.
EDIT: Fixed a mistake with explaining the precedence.
Nothing after the || is evaluated, since the result of the expression ++i is nonzero.

Resources