I was taking a practice programming quiz, and I'm not sure why this program prints out -1:
#include <stdio.h>
int main()
{
int x = 1;
if (x-- && x-- && x--)
{
printf("%d\n", x);
} else
{
printf("%d\n", x);
}
return 0;
}
In C, logical operators such as && and || are evaluated using short-circuit evaluation, which essentially means that when a statement is guaranteed to be either true or false, any subsequent expressions in the statement are not evaluated.
In your program, only the first two conditions need to be evaluated to determine that the whole statement is false. The third expression is not evaluated.
if (x-- && /* evaluates true, and then x is decremented */
x-- && /* evaluates false, and then x is decremented */
x--) /* this is not executed */
Because this is a series of AND statements, logically, only one expression needs to be false for the whole statement to be false. When the second expression is determined to be false, there's no need to waste resources by evaluating the rest of the statement, so the else block is executed.
This causes the final value of x to be -1, instead of -2.
In C language, the test statement would end its operation as soon as the result can be determined. In this case, the first x-- returns 1 and set x = 0, the second x-- returns 0 and set x = -1.
1 && 0 can determine the result as 0, so the last x-- is ignored.
With a FALSE statement, the if-else choose the second printf as output and print the value of x : -1;
First start with x = 1, then the sequence of x-- && x-- && x-- goes like this, where each x-- represents the respective part of the condition.. (note that && acts as a sequence point).
x = 1 -> x = 1
x-- -> 1, x = 0
The result is 1 (1 && x-- && x--) so right-hand express of the first && is evaluated.
x-- -> 0, x = -1
The result is 0 (1 && 0 && x--) and the && short-circuit evaluation kicks in and the right-hand expression of the second && is not evaluated.
x--
Nope; as above this was not evaluated.
Since the condition is false (1 && 0 && dont_care_not_evaluated) it prints out the value, in the else case, while having only decremented x twice.
x-- -> 1-- it returns 1 here, after it gets decrements to 0
x-- -> 0-- it returns 0 here, what means false, after it gets decremented x to
x-- -> its unreahched, because this is an and condition, it stops if a part of it is false
so the final value will be -1 (what is not 0, so -1 is interpreted as true)
Related
What does this statement tell please explain if(!(!x) && x)
#include<stdio.h>
int main(){
int x=5, y=10;
if(!(!x) && x)
printf("%d",x);
else
printf("%d",y);
return 0;
}
if(!(!x) && x) is equivalent to if(!!x && x).
!!x is 1 if x is non-zero and 0 if x is zero.
Furthermore, the expression simplifies to (!!x) since && x is a tautology as x is a non-volatile int type. But this collapsing the value to either 0 or 1 is exactly the behaviour of the if conditional, so the if simplifies to if (x).
In c, true and false are 1 and 0 respectively.
!(!x)
If x is zero, then (!x) evaluates as true (1), then !(true) evaluates as false.
The if statement is always false in such case.
if(!(!x) && x)
However, if x was non-zero, then !!x is true
true && true
You could simplify this if statement with
if(x)
Looking at the assembly generated by GCC 10.1 on https://godbolt.org/z/7kwDdJ
xor eax, eax // eax = 0
test edi, edi // perform bitwise & and set Zero, Positive, or Negative flag
sete al // Sets lower 8-bits in eax to 1 if the zero flag is set or to 0 otherwise.
ret
In short, GCC is reducing if(!(!x) && x) to if (x & x)
! is the not operator. It reverses 1 to 0 and vice versa. In your problem !(!x)
evaluates to x and so (!(!x) && x) will evauate to a true condition so x will be printed
In C language non-zero values are considered True and zero(0) is considered False. On the other hand, Logical Not (!) operator determines the opposite of something. For example: in your code, x = 5, So the value of !x will be 0, because x = 5 means the variable x holds a true value. So, not true = false = 0. Then the value of !(!x) = !(false/0) = not false = true = 1.
Remember that, logical NOT(!) operator doesn't change the value.
So ultimately !(!x) means true.
if(!(!x) && x) = if(true && true) = if(true)
This is why, if block will be executed.
I am not getting expected output in the following C code
main(){
int i=0,j=-2,k=0,m;
if((!i||--j&&k++)&&(i++||j++&&!k++))
{
printf("i=%d j=%d k=%d",i,j,k);
}
return 0;
}
I got the output in compiler as :
i=1 j=-1 k=1
But I don't understand what exactly is going on here.
I think the if statement should not run since its argument is false
Note the first bracket (!i||--j&&k++)
here as !i=1 hence this bracket is true since anything with 1 under OR operator will be true.
out values become: i=0, j=-3, k=1
Now notice the second bracket: (i++||j++&&!k++)
Here we have ( 0 || -3 && !1) = 0, false
as the brackets are separated by &&, the whole argument of if statement becomes false.
Please explain me where my argument is wrong. I am a new to C
The logical AND operator && and the logical OR operator || are short circuit operators, meaning that the right side won't be evaluated if the result of the expression can be determined from the left side.
So when this subexpression runs:
(!i||--j&&k++)
Which is parsed as:
(!i||(--j&&k++))
The left side of the || evaluates to true, so --j&&k++ is not evaluated, meaning the value of j remains -2 and the value of k remains 0.
So the left side of the outermost && is true, so now we evaluate the right side:
(i++||j++&&!k++)
Which is parsed as:
(i++||(j++&&!k++))
i is incremented to 1, then the old value is used in ||. The old value of 0 evaluates to false so the right side is evaluated. j is incremented to -1 and the old value of -2 evaluates to true, so the right side of && is evaluated. k is incremented to 1 and the old value of 0 is applied to the ! operator which evaluates to true. This makes the entire expression true and the statement is printed, at which time i is 1, j is -1, and k is 1.
Let’s spread this out a little to make reading it easier:
int i = 0, j = -2, k=0, m;
(!i || --j && k++) && (i++ || j++ && !k++)
As you note !i is true (value 1), so the || is true. The || operator is defined not to evaluate its right operand if the left operand is true, so --j && k++ is not evaluated and has no effect. (The right operand is --j && k++ because && has higher precedence than ||, so A || B && C is structured as A || (B && C).)
That settles the left operand of the central &&. In the right operand, i++ increments i to 1 but evaluates to the current value of i, 0, so it is false for the purposes of the || operator. So the right operand of that || is evaluated.
That operand is j++ && !k++. Since j is −2, j++ changes j to −1 and evaluates to −2, which is a value of true for the purposes of &&. Then k++ increments k to 1 but evaluates to 0, and !k++ changes this to 1, yielding true for the && and therefore true for the previous || and the central &&.
At this point i is 1, j is −1, and k is 1, which is the result you got.
you may be missing that if statements ends once they are satisfied, so (!i||--j&&k++) is only going to compute i and the other operations are going to be disregarded. By that I mean j is going to be -2 by the end of the first statement.
I understand a condition is supposed to be for example y==3, but y-3 is totally confusing to me. I can't understand this code. If y-3 is true it prints 1. How can y-3 be true or false?
The expression y - 3 results in a value which can be tested for truthness. In C 0 is false and any non-zero value is true. Saying if (y - 3) is essentially saying if (y - 3 != 0) or even more succinctly if (y != 3)
In C, everything what's 0 is false and everything what's non-zero is true.
When tested directly into a boolean context, integers can be evaluated like this.
0 is equivalent to false and all the other values are considered true.
In your code y - 3 will be equivalent to false only if y - 3 == 0, that is if y is 3.
A better style would be to write:
if (y - 3 != 0)
Or even:
if (y != 3)
if (E)
where E is an expression is equivalent to
if (E != 0)
In an if statement (or any statement with a condition), the condition is considered true if it's unequal to zero, false otherwise.
So this:
if (y - 3)
is equivalent to this:
if ((y -3 ) != 0)
which can (and should!) be re-written as:
if (y != 3)
The == operator, for example, yields an int value of either 1 or 0.
C does have a built-in Boolean type (called _Bool, introduced by the 1999 standard), but it didn't always exist, and it's not used in conditions. Of course you can use a _Bool value as a condition, but it's still tested (at least conceptually) for inequality to zero.
First, the expression 'y-3' will be evaluated. If the result is 0 (a.k.a, the value of y is 3), then the expression will evaluate to false, and the value "2" will be printed. If y is equal to any value other then 3, the condition will evaluate to true, and the value "1" will be printed
This would mean exactly the same
if ((y - 3) != 0)
printf("1");
else
printf("2");
So that's going to be true if it's not zero.
I don't know if anyone could kindly explain this code for me?
unsigned int x = 0;
(x ^= x ) || x++ || ++x || x++;
printf("%d\n", x);
when I compile this on my computer using gcc 4.2, the output is 2.
Originally i thought maybe this behavior is unspecified but then i figure || will have lower precedence over other operators, so shouldn't the answer be 3? Since there are three "++".
Can someone explain? Thanks
(x ^= x) is evaluated and it yields 0, therefore:
(x++) is evaluated and it yields 0, therefore:
(++x) is evaluated and it yields 2, therefore it stops
It all boils down to one rule: || only evaluates its right side if its left side is false.
The issue is that the || operator is short-circuiting. As soon as it finds a true value, it no longer needs to check the remaining || statements; the answer is already known.
(x ^= x) evaluates to 0.
x++ evaluates to 0, then increments x to 1.
++x evaluates to 2 -- true.
The final or statement does not need to be computed. It "short-circuits" and immediately returns true.
The behaviour is well-defined. You are observing the short-circuiting behaviour of ||; the final x++ is never evaluated.
That is short-circuit semantics in action. The first expression x ^= x evaluates to 0, the second evaluates to 0 as well. The third one evaluates to 2, and then the logical expression is short-circuited since its result its already determined to be true.
Of course you shouldn't use such constructs, but let us analyze the expression.
There are 4 expressions combined with shortcut-OR:
a || b || c || d
b, c and d are only evaluated, if a is false, c and d only if b is false too, and d only if all from the before are false.
Ints are evaluated as 0 == false, everything else is not false.
x ^= 0
with x being 0 is 0 again.
x++
is evaluated and later increased, so it evaluates to 0, which invokes expression c, but later x will be increased.
++x
is first incremented, leading to 1, and then evaluated (leading to 1) which is the reason, why d is not evaluated, but the increment of b is pending, so we get 2.
But I'm not sure, whether such behaviour is exactly defined and leads to the same result on all compilers.
Avoid it.
The expressions between the || operators will be evaluated left to right until one is true:
(x ^= x )
Sets all bits in x to 0/off. (false);
x++
Increments x, it's now 1, but still false because this was a post increment.
++x
(pre-)Increments x, which is now 2 and also true, so there is no need for the right hand side of || to be evaluated.
Why does this code always produce x=2?
unsigned int x = 0;
x++ || x++ || x++ || x++ || ........;
printf("%d\n",x);
the 1st x++ changes x to 1 and returns 0
the 2nd x++ changes x to 2 and returns 1
at which point the or short circuits, returns true, and leaves x at 2.
x++ || x++ || x++ || x++ || ........;
First x++ evaluates to 0 first for the conditional check, followed by an increment. So, first condition fails, but x gets incremented to 1.
Now the second x++ gets evaluated, which evaluates to 1 for the conditional check, and x gets incremented to 2. Since expression evaluates to 1 (true), there's no need to go further.
Because of short circuit in boolean expression evaluation and because || is a sequence point in C and C++.
|| short-circuits. Evaluated from left, when a true value is found (non-zero) it stops evaluating, since the expression now is true and never can be false again.
First x++ evaluates to 0 (since it's post-increment), second to 1 which is true, and presto, you're done!
When you're evaluating "a || b || c || d || e || ..." you can stop evaluating at the first non-zero value you find.
The first "x++" evaluates to 0, and increments x to 1, and evaluating the expression continues. The second x++ is evaluated to 1, increments x to 2, and at that point, you need not look at the rest of the OR statement to know that it's going to be true, so you stop.
Because logical OR short-circuits when a true is found.
So the first x++ returns 0 (false) because it is post-increment. (x = 1)
The second x++ returns 1 (true) - short-circuits. (x = 2)
Prints x = 2;
Because of early out evaluation of comparisons.
This is the equivalent of
0++ | 1++
The compiler quits comparing as soon as x==1, then it post increments, making x==2
Because the first "x++ || x++" evaluates to "true" (meaning it is non zero because "0 || 1" is true. Since they are all logical OR operators the rest of the OR operations are ignored.
Mike
The || operator evaluates the left-hand expression, and if it is 0 (false), then it will evaluate the right-hand expression. If the left hand side is not 0, then it will not evaluate the right hand side at all.
In the expression x++ || x++ || x++ || ..., the first x++ is evaluated; it evaluates to 0, and x is incremented to 1. The second x++ is evaluated; it evaluates to 1, and x is incremented to 2. Since the second x++ evaluated to a non-zero value, none of the remaining x++ expressions are evaluated.
trying replacing || with |.--
It is the short circuiting of logical operators.
It's the same reason when you do
if (returns_true() || returns_true()){ }
returns_true will only get called once.