So I was reading about the order of different operators, and I read that && has higher importance than || and it would evaluate sooner (source). Then somebody asked a question about what this piece of code would print:
#include <stdio.h>
int main(){
int a=0, b=0, c=0, d=0;
if(a++>0 || ++b==1 || c--<=0 && d++>c--){
printf("if\na:%d\nb:%d\nc:%d\nd:%d\n",a,b,c,d);
}
else{
printf("else\na:%d\nb:%d\nc:%d\nd:%d\n",a,b,c,d);
}
return 0;
}
And I thought that the c-- <= 0 && d++ > c-- would evaluate first, which is true in total. after the process, c would be equal to -2 and d would be equal to 1. Then it would start checking from the left side, evaluating a++ > 0 || ++b == 1 which is true, a would be 1 at the end and b is 1 in the condition and after that. so the total condition would be true || true and it is true, so we will print:
if
a:1
b:1
c:-2
d:1
Yes? Apparently, no. I've tested it with GCC (Mingw) on my system (Windows 10), and with an online compiler (this one) and both printed:
if
a:1
b:1
c:0
d:0
I've changed the condition into this: if(a++>0 || ++b==1 || (c--<=0 && d++>c--) ) but the output is the exact same thing on both places. Is there something that I don't pay attention to? Or is this something like a bug? It almost looks like that || and && have the same priority and the whole thing is evaluated from the left side, and short-circuits occurs and other things. If I change the ++b==1 part into ++b==0, then the output is the same as I predicted.
Thanks in advance for any kind of help :)
The expression in this question:
if(a++>0 || ++b==1 || c--<=0 && d++>c--)
is a classic example of a horrible, horrible expression, outrageously unrealistic and impractical, and punishingly difficult to understand, which nevertheless does a good job of illustrating a super important point: precedence is not the same as order of evaluation.
What precedence really tells us is how the operators are hooked up with their operands. So given the simplified expression
A || B || C && D
which two subexpressions do the first ||, and the second ||, and the && actually tie together and operate on? If you're a compiler writer, you answer these questions by constructing a "parse tree" which explicitly shows which subexpression(s) go with which operators.
So, given the expression A || B || C && D, does the parse tree for the expression look like this:
&&
/ \
|| D
/ \
|| C
/ \
A B
or like this:
||
/ \
A ||
/ \
B &&
/ \
C D
or like this:
||
/ \
/ \
|| &&
/ \ / \
A B C D
To answer this, we need to know not only that the precedence of && is higher than ||, but also that || is left-associative. Given these facts, the expression
A || B || C && D
is parsed as if it had been written
(A || B) || (C && D)
and, therefore, results in the third of the three candidate parse trees I showed:
||
/ \
/ \
|| &&
/ \ / \
A B C D
But now we're in a position to really see how the "short circuiting" behavior of the || and && operators is going to be applied. That "top" || is going to evaluate its left-hand side and then, if it's false, also evaluate the right-hand side. Similarly, the lower || is going to evaluate its left-hand side. So, no matter what, A is going to get evaluated first. For the expression in the original question, that corresponds to a++ > 0.
Now, a++>0 is false, so we're going to have to evaluate B, which is ++b == 1. Now, that is true, so the result of the first || is "true".
So the result of the second (top) || operator is also "true".
So the right-hand side of the top || operator does not have to be evaluated at all.
So the entire subexpression containing && will not be evaluated at all.
So even though && had the highest precedence, it ended up getting considered last, and (since the stuff to the left involved || and was true) it did not end up getting evaluated at all.
The bottom line, as I started out by saying, is that precedence does not determine order of evaluation.
Also, if it wasn't said elsewhere, this guaranteed, left-to-right behavior is only guaranteed for the || and && operators (and, in a different way, for the ternary ?: operator). If the expression had been
A + B + C * D
it would not have been true that, as I said earlier, "no matter what, A is going to get evaluated first". For arithmetic operators like + and *, there's no way to know whether the left-hand side or the right-hand side is going to get evaluated first.
Related
In the follwing code,
int a = 1, b = 2, c = 3, d;
d = a++ && b++ || c++;
printf("%d\n", c);
The output will be 3 and I get that or evaluates first condition, sees it as 1 and then doesn't care about the other condition but in c, unary operators have a higher precedence than logical operators and like in maths
2 * 3 + 3 * 4
we would evaluate the above expression by first evaluating product and then the summation, why doesn't c do the same? First evaluate all the unary operators, and then the logical thing?
Please realize that precedence is not the same concept as order of evaluation. The special behavior of && and || says that the right-hand side is not evaluated at all if it doesn't have to be. Precedence tells you something about how it would be evaluated if it were evaluated.
Stated another way, precedence helps describe how to parse an expression. But it does not directly say how to evaluate it. Precedence tells us that the way to parse the expression you asked about is:
||
/ \
/ \
&& c++
/ \
/ \
a++ b++
But then when we go to evaluate this parse tree, the short-circuiting behavior of && and || tells us that if the left-hand side determines the outcome, we don't go down the right-hand side and evaluate anything at all. In this case, since a++ && b++ is true, the || operator knows that its result is going to be 1, so it doesn't cause the c++ part to be evaluated at all.
That's also why conditional expressions like
if(p != NULL && *p != '\0')
and
if(n == 0 || sum / n == 0)
are safe. The first one will not crash, will not attempt to access *p, in the case where p is NULL. The second one will not divide by 0 if n is 0.
It's very easy to get the wrong impression abut precedence and order of evaluation. When we have an expression like
1 + 2 * 3
we always say things like "the higher precedence of * over + means that the multiplication happens first". But what if we throw in some function calls, like this:
f() + g() * h()
Which of those three functions is going to get called first? It turns out we have no idea. Precedence doesn't tell us that. The compiler could arrange to call f() first, even though its result is needed last. See also this answer.
This question already has answers here:
Evaluation of the following expression
(3 answers)
Closed 3 years ago.
As I know logical operator && has higher precedence than ||. On running the code:
#include <stdio.h>
int main()
{
int i = 1, j =1, k = 1;
printf("%d\n",++i || ++j && ++k);
printf("%d %d %d",i,j,k);
return 0;
}
is giving the output:
1
2 1 1
which is possible only when ++i || ++j && ++k is evaluated like this:
(++i) || (++j && ++k)
But, according to operator precedence rule it should be evaluated as:
(++i || ++j) && (++k)
and hence output should be:
1
2 1 2
What is going wrong with this?
NOTE: As per my understanding I think an operator of higher precedence evaluated as follows(if it is left associative):
1. Evaluate its left expression
2. Then evaluate its right expression(if needed)
Am I wrong?
The || operator short-circuits - if its first operand evaluates to true (nonzero), it doesn't evaluate its second operand.
This is also true for &&, it doesn't use its second operand if the first one is false. This is an optimization that's possible because any boolean value OR true is true, and similarly, any boolean value AND false is always false.
OK, so you're confusing precedence with evaluation order. Nothing is contradictional here at all:
++i || ++j && ++k
is grouped as
(++i) || (++j && ++k)
since && has higher precedence. But then the LHS of the OR operation is true, so the whole RHS with its AND operation is discarded, it isn't evaluated.
To your note in the edit: yes, you're wrong: operator precedence is still not the same as order of evaluation. It's just grouping.
You say:
which is possible only when ++i || ++j && ++k is evaluated like this:
(++i) || (++j && ++k)
But, according to operator precedence rule it should be evaluated as:
(++i || ++j) && (++k)
The first grouping is correct because the precedence of && is higher than the precedence of ||. Then the expression as a whole evaluates the LHS of the ||, with the side-effect of incrementing i, which evaluates to true. That means that the RHS of the || (the && expression) is not evaluated at all because it is not needed to determine the truth of the overall expression.
So, the compiler is correct; you misunderstood precedence in some way.
Why is the first grouping correct? According to first grouping || has higher precedence than &&. What is going wrong with me?
You don't understand precedence, it seems, or you don't understand the interaction of precedence with order of evaluation. The first grouping gives higher precedence to &&.
If you have a + b * c, where * has a higher precedence than +, then it is evaluated as a + (b * c), is it not? Change + to || and * to && and the expressions are isomorphic and the interpretation is similar.
The big difference between the arithmetic expression and the logical expression is that the operands of the logical expression have to be evaluated left-to-right but the operands of the arithmetic expression do not; the compiler could evaluate b * c before evaluating a (but must evaluate b * c before doing the addition). By contrast, in the logical expression (a || b && c), the compiler must evaluate a before evaluating b && c, and when a turns out to be true, it must not evaluate either b or c, let alone b && c.
Firstly, as you said it yourself, && has higher precedence, which means that operand grouping should be
(++i) || (++j && ++k)
Why you are saying that "according to operator precedence" it should be (++i || ++j) && (++k) is not clear to me. That just contradicts what you said yourself.
Secondly, operator precedence has absolutely nothing to do with order of evaluation. Operator precedence dictates the grouping between operators and their operands (i.e. operator precedence says which operand belongs to which operator).
Meanwhile, order of evaluation is a completely different story. It either remains undefined or defined by completely different set of rules. In case of || and && operators the order of evaluation is indeed defined as left-to-right (with mandatory early completion whenever possible).
So, operator precedence rules tell you that the grouping should be
(++i) || ((++j) && (++k))
Now, order-of-evaluation rules tell you that first we evaluate ++i, then (if necessary) we evaluate ++j, then (if necessary) we evaluate ++k, then we evaluate && and finally we evaluate ||.
Since you are misunderstanding precedence, let's try to clear it up with a mathematical example. Multiplication and division have a higher precedence than addition and subtraction. Which means that this expression:
a + b * c - d / e
Can be written like this:
a + (b * c) - (d / e)
Since you correctly stated that && has higher precedence than ||, this expression:
i || j && k
can be written like this:
i || (j && k)
You can think of it as "the operation with the highest precedence gets parenthesized first", if that helps.
(But precedence is different from evaluation - if i is true, then (j && k) will never be evaluated.)
This question already has answers here:
Why does "++x || ++y && ++z" calculate "++x" first, even though operator "&&" has higher precedence than "||"
(11 answers)
Closed 4 years ago.
The O/p comes out to be x=2,y=1,z=1 which doesnt agree with the operator precedence. I was running this on Turbo c++ compiler:
void main()
{
int x,y,z,q;
x=y=z=1;
q=++x || ++y && ++z;
printf("x=%d y=%d z=%d",x,y,z);
}
Actually the result is in complete accordance with standard C. The logical or operator (||) short circuits after ++x because it evaluates to a non-zero number, so the rest of them are ignored.
So starting at x=1, y=1, z=1, after the short circuit, you get x=2, y=1, z=1.
Operator precedence does not in any way determine the order in which the operators are executed. Operator precedence only defines the grouping between operators and their operands. In your case, operator precedence says that the expression
q = ++x || ++y && ++z
is grouped as
q = ((++x) || ((++y) && (++z)))
The rest has absolutely nothing to do with operator precedence at all.
The rest is determined by the semantics of each specific operator. The top-level operator in this case is ||. The specific property of || operator is that it always evaluates its left-hand side first. And if the left-hand size turns out to be non-zero, then it does not even attempt to evaluate the right-hand side.
This is exactly what happens in your case. The left-hand side is ++x and it evaluates to a non-zero value. This means that your whole expression with the given initial values is functionally equivalent to a mere
q = (++x != 0)
The right-hand side of || operator is not even touched.
x=y=z=1;
Makes all the variables = 1
q=++x || ++y && ++z;
Since ++x makes it = 2 and since it is not zero it stops checking the other conditions because the first one is true.
Thus, x=2, and y and z = 1
Logical && (AND) and || (OR) operators are subject to Short-Circuit.
"Logical operators guarantee evaluation of their operands from left to right. However, they evaluate the smallest number of operands needed to determine the result of the expression. This is called "short-circuit" evaluation."
Thus, for logical operators always evaluated as (no matter || or &&) left to right.
And as previously mentioned, precedence here only determines who takes who.
Then left to right rule;
q = ++x || ++y && ++z;
//ok, lets play by rule, lets see who takes who:
//first pass ++ is badass here (has highest precedence)
//q = (++x) || (++y) && (++z)
//second pass &&'s turn
//q = (++x) || ((++y) && (++z))
//done, let's do left to right evaluation
q = (++x) || rest..
q = (true)|| whatever..
hope that helps more clear.
As we all know that Associativity of assignment operator is from right to left but
in the given code output should be zero if we go from right to left but output is 1 .
main()
{
int a=3,b=2;
a=a==b==0;
printf("%d",a);
}
How output is coming out to be 1 if we go by right to letf??
If we go by right to left then (b==0) should be Evaluated first and gives result 0 and then expression (a==0) is Evaluated also gives 0 and at last a's value will be 0.
Assignment is done RTL, but equality (==) isn't.
The statement is actually:
a = ((a == b) == 0)
The right hand side of the assignment is evaluated from left to right. In steps, this is what's happening:
a == b is 0
0 == 0 is 1
1 is assigned to a
Your code is equivalent to :
a = ((a == b) == 0);
Note, this is phrased this way as it was merged from this question. OP asked why a==b==c is equivalent to a==b && b==c in Objective C (which is a strict superset of C). I asked this answer to be migrated since it cites the specificatio where other answers here do not.
No, it is not, it's like (a==b) == c.
Let's look at a simple counter example to your rule:
(0 == 0 == 0);// evaluates to 0
However
(0 == 0) && (0 == 0) // evaluates to 1
The logic is problematic since:
(0 == 0 == 0) reads out as ((0 == 0) == 0) which is similar to 1 == 0 which is false (0).
For the ambitious student
A little dive on how this is evaluated. Programming languages include grammar which specifies how you read a statement in the language. Siance Objective-C does not have an actual specification I'll use the C specificification since objective-c is a strict superset of c.
The standard states that an equality expression (6.5.9) is evaluated as the following:
Equality Expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
Our case is the second one, since in a == b == c is read as equality_expression == relational_expression where the first equality expression is a == b.
(Now, the actual result number follow quite a way back to a number literal, equality->relational->shift->additive->multiplicative->cast->unary->postfix->primary->constant , but that's not the point)
So the specification clearly states that a==b==c does not evaluate the same way as a==b && b==c
It's worth mentioning that some languages do support expressions in the form a<b<c however, C is not one such language.
pretty simple question I have here, but I couldn't find the answer:
Assume I have some conditional clause made up of several conditions. E.g. something like
if((a == b && strcmp(string1, string)) || x <= 5)
My question is: Will all of those statements be evaluated, no matter what the result of the first ones was, or will the evaluation stop once the result is clear.
As I am not sure whether my question is clear, here's an example:
if(a == 5 || b > 12 || (c = someFun()) == 3)
In this case, if a == 5, no further checks would be required, because the result of the big statement is TRUE, so we could simply continue. This would mean that someFun() would not be evaluated.
Is this the case? I know Java makes a difference here between && and & resp. || and | (the latter aren't available in C anyways), but I do not know how C handles this
These operators are short-circuiting in C (and C++).
C evaluates until it knows the answer, so:
EvalsToTrue() && EvalsToAnything() evaluates both
EvalsToFalse() && EvalsToAnything() evaluates only the first
EvalsToTrue() || EvalsToAnything() evaluates only the first
EvalsToFalse() || EvalsToAnything() evaluates both
The left-hand side expression is always evaluated. The right-hand side expression is evaluated as follows:
a || b -- b will be evaluated only if a evaluates to false
a && b -- b will be evaluated only if a evaluates to true
&& has higher precedence than ||, thus
a || b && c -- b && c will be evaluated only if a evaluates to false
a && b || c -- c will be evaluated only if a && b evaluates to false
(a || b) && c -- c will be evaluated only if a || b evaluates to true
a && (b || c) -- b || c will be evaluated only if a evaluates to true
a && b && c -- c will be evaluated only if a && b evaluate to true
a || b || c -- c will be evaluated only if a || b evaluate to false
Evaluation starts at left most.. and exits when the overall condition is no longer valid..