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.
Related
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.
Let me be judged as a Noob in programming, I have been learning obfuscated way of programming in c/c++, as the c compiler compiles a statement from the right hand side towards the left hand side.
I have the following code:
int main(){
int x=5, y=20, z=1;
int k = x > y < z;
printf("%d", k);
return 0;
}
The output returned is 1, Does this means that
x > y < z = (x>y) < z
or
x > y < z = x > (y<z)
I would love if someone would give me link to work on these skills.
Thanks and Regards.
Change z=-1 or x=0 and find out. Also change int main() to the more correct int main ( void )
Changing z = -1 will ouput 0, whereas k will be 1 if you assign it x > y == z if z = 0. So in short:
k = x > y < z;
is the same as writing
k = (x > y) < z;
left-to-right.
According to the C grammar (6.5.8 Relational operators)
1 relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
1 The relational operators group left-to-right (C++ Standard :) )
And
6 Each of the operators < (less than), > (greater than), <= (less than
or equal to), and >= (greater than or equal to) shall yield 1 if the
specified relation is true and 0 if it is false.107) The result has
type int.
Thus the initializer in this declaration
int k =x>y<z;
is equivalent to
int k = ( x > y ) < z;
As x is less than y then expression x > y yields 0 and as z is greater than 0 then the full expression yields 1.
The following operators have right-to-left-grouping:
unary operators
conditional operator
assignmnet and compound assignment operators
First you have to check operator precedence, which is easiest by looking at an operator precedence table. If such a table is decent, it will list the operators > and < in a group called relational operators. All operators in this group have the same operator precedence.
Since the operators > and < have the same precedence, the order in which the operands will get processed is determined by the associativity of that group of operators. For the relational operators, this is left-to-right. Therefore the expression is guaranteed to be processed as (x > y) < z
In C the boolean values are numerical values, so:
false -> 0
true -> != 0, hence any number that is not 0 will represent the boolean true.
So in case of your code:
int k = x > y < z;
can be split in the following way:
int k = (x > y) < z;
that will be:
int k = ( 5 > 20) < 1;
the first part evaluates to false (0 that is) then the equality will loook this way:
int k = 0 < 1;
which is true, hence
int k = 1;
k = ( 5 > 20 ) < 1= False (0)
k = (0 < 1) = True (1)
printf (%d, k) = 1
Maybe you should know the Operator precedence and associativity. You can google or see the book <<c++ primer>>. First the operator > and < have a same precedence. Then we should use the associativity, there the operator only have left associativity. So the answer is x> y< z= (x>y)<z). I hope this can help you. Remember: 1. precedence; 2. associativity.
Can anyone explain me why this line of code is wrong?
int n = 0, y = 1;
y == 1 ? n = 0 : n = 1;
The error is "Lvalue required as left operand of assignment " for "n=1"
The statement
(y == 1 ? n = 0 : n) = 1;
is interpreted as because n binds with ?: operator due to its higher precedence.
= needs l-value as its left operand while ?: returns an r-value.
Try this instead
y == 1 ? n = 0 : (n = 1);
or
n = y == 1 ? 0 : 1;
You should use :
n = y==1 ? 0 :1
According to the C standard, the behaviour is undefined if an attempt is made to use the result of the conditional operator as an Lvalue.
You can use ternary operator for assigning for example:
int n = 0, y = 1;
n = y == 1 ? 0 : 1;
I am beginner in C programming language, recently I have read about Logical AND && operator.
I also know that, in C programming language all non-zero values are treated as TRUE.
NON-ZERO && NON-ZERO = 1
NON-ZERO && ZERO = 0
ZERO && NON-ZERO = 0
ZERO && ZERO = 0
But when I am dealing with the following program then I am not getting expected answer.
int main(){
int x, y, z;
x = y = z = -1;
y = ++x && ++y && ++z;
printf("x = %d, y = %d, z = %d, x, y, z);
return 0;
}
I am expecting
x = 0, y = 0, z = 0
but the answer is
x = 0, y = 0, z = -1
Can anyone please explain, Why I am getting this answer?
Edit:
In this question, I have not asked about the precedence of operators.
Because of Short-circuit evaluation, when x is 0, y and z don't really need to be evaluated since 0 && ANYTHING is 0.
Once x is incremented to 0, the result is 0, and that's what y gets.
z remains unchanged (-1).
x | y | z
----+----+-----
-1 | -1 | -1 //x = y = z = -1;
0 | -1 | -1 //++x && ... Now the whole expression is evaluated to 0
0 | 0 | -1 //y = ++x && ++y && ++z;
I only can think about that && evaluates in short circuit: given A && B, if A evaluates false then B is not evaluated.
So:
X becomes 0. && ++y && ++z does not evaluates since X/0/false && ...
y=0 as assigned from y = x/0/false
z remains unmodified since ++z does not get executed.
&& operator is evaluated pairwise, therefore I'm guessing C is evaluating
((++x && ++y) && ++z)
now, ++x will return zero therefore the first && will fail as will the second one without the need to evaluate ++y or ++z.
y = 0 since that is the result of the expression.
z is not touched
What happens is that ++y and ++z are never evaluated because the first part already ensures what the new value of y will be.
The first part of your statement is ++x && ... which is equivalent to 0 && ... and then we already know that y will be 0 in the end so the rest of the statement is not executed.
if you did this:
int main(){
int x,y,z,tmp;
x = y = z = -1;
tmp = ++x && ++y && ++z;
printf("x = %d, y = %d, z = %d, tmp = %d", x,y,z, tmp);
return 0;
}
You would get x = 0, y = -1, z = -1, tmp = 0
The left evaluation is guaranteed in the C99 standard. You can find it in the section 6.5.13 Logical AND operator
Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation;
there is a sequence point after the evaluation of the first operand. If the first operand
compares equal to 0, the second operand is not evaluated.
You can find more information about what is a sequence point on Wikipedia or in the Annex C of the C99 standard
For completeness (brain dump):
The term behind this sorcery is called short circuiting. Let's go over your code and then a brief blurb about why this happens. Looking at:
int main( void ) {
int x, y, z;
x = y = z = -1;
y = ++x && ++y && ++z;
printf( "x = %d, y = %d, z = %d, x, y, z );
return 0;
}
... we begin to break it down line by line. The first line:
int x, y, z;
... declares three integers, x, y and z. They are initialized to garbage values on the stack frame because there is no initialization (assignment operator). This line does not really matter, now let's look at the next one:
x = y = z = -1;
... we see that we are doing multiple assignments on the same line. Recall that the assignment operator will mutate the identifier to the left of the assignment operator (using the value to the right of the assignment operator) and return the value of x. This is known as assignment overloading. But again, this does not really matter -- the only important thing to realize is x, y and z are now all -1. Let's look at the next line:
y = ++x && ++y && ++z;
... Sorcery Yoda says. Let's add the parenthesis to make it more obvious which step is being evaluated first:
y = ( ( ++x ) && ++y && ++z );
... now looking at the inner-most parenthesis we see that it's a prefix increment of x, meaning we will increment the value of x and then return it. We note that x is originally -1 and it is now 0 after being incremented. This will resolve as follows:
y = ( 0 && ++y && ++z );
... now it's important to note that looking at our truth tables:
A | B | A && B
--------------
T | T | T
T | F | F
F | T | F
F | F | F
... for the AND logical operator we see that both F (AND) T, T (AND) F are F. The compiler realizes this and short circuits when ever it is evaluating a conjunction (AND) where a value is false -- a clever technique of optimization. It will then resolve to assigning y to be 0 (which is false). Recall that in C any non-zero value is true, only 0 is false. The line will look as follows:
y = 0;
... now looking at the next line:
printf( "x = %d, y = %d, z = %d, x, y, z );
... it should be obvious to you now that it will output x = 0, y = 0, z = -1.
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.