I have the following code which produces unexpected results to me:
#include < stdio.h >
int a = 0, value;
int main(void)
{
// Testing the evaluation order of multiple
// conditional operators:
value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
printf("%d\n", value);
return 0;
}
I was expecting for this code to print 3, seeing that the conditional operator evaluates
from right to left and that there is a sequence point at the ? of the first-to-be executed
operation, whereas it actually prints 5.
Is it wrong to assume that side effects of an expression residing between two sequence
points also get calculated when the values of the expressions are?
If i add printf("%d\n" a); i get 3 printed though, so the side effect gets done.
Or is it just that control dosent really pass to the subexpression the value of which
is being calculated "first" officially?
I would rather bet on the latter because changing the value of 'a' to 3 and the rvalue
in the assignment of the second conditional to 4 resulted in short-circuit evaluation
of the first conditional expression, meaning that i got 3 printed for both 'a' and 'value'.
I got the above result on Lubuntu 14.04 with GCC 4.8.2 using the -std=c99 flag.
Thank you for anyone clearing me up on this matter!
The conditional operator does not "evaluate right to left". The standard (C11 6.5.15/4) says:
The first operand is evaluated; there is a sequence point between its
evaluation and the evaluation of the second or third operand
(whichever is evaluated). The second operand is evaluated only if the
first compares unequal to 0; the third operand is evaluated only if the
first compares equal to 0; the result is the value of the second or
third operand (whichever is evaluated)
So the expression (a == 3) ? 3 : (a = 3) ? 5 : 0; evaluates in these steps:
(a == 3) result is 0
(a = 3) result is 3, unequal to 0
5
So 5 is what is assigned to value.
You might be confusing the concept of how the conditional operator is evaluated with how the conditional operator associates (or groups). The syntax of C specifies that the expression:
(a == 3) ? 3 : (a = 3) ? 5 : 0;
associates or groups sub expressions like so:
((a == 3) ? 3 : ((a = 3) ? 5 : 0));
which is often described as 'associates right'. However, this grouping/associativity doesn't affect the fact that the expression is still evaluated left-to-right and that the second conditional expression only evaluates after the first operand in the 'outer' conditional expression is evaluated.
Let's trace through this one part at a time. You have this expression:
value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
Since a starts off at 0, we skip the 3 branch of the first ?: and look at the second branch, which is
(a = 3) ? 5 : 0
The condition here is a = 3, which sets a to 3 and then evaluates to the new value of a, which is 3. Since 3 is nonzero, we take the first branch of the ?:, so the expression evaluates to 5. The net effect is that a is set to 3 and value is set to 5.
The language spec guarantees that the evaluation order is indeed what you think it should be - the "if" and "else" branches of the ?: operator are guaranteed not to execute unless the condition works out as it does, so there are sequence points here. I think you just misunderstood the effect of the a = 3 operation.
Hope this helps!
The conditional operator evaluates left-to-right (evaluating the condition before either of the branches). You may be confusing this with its right-associativity (in which it appears to bind right-to-left).
Your conditional expression essentially results in the following logic:
if(a == 3) {
value = 3;
} else {
if(a = 3) {
value = 5;
} else {
value = 0;
}
}
Note that the conditional doesn't execute a branch until after the condition is evaluated.
Related
#include <stdio.h>
int main() {
int a = 1;
int b = a || (a | a) && a++;
printf("%d %d\n", a, b);
return 0;
}
when I ran this code the results were 1 and 1.
According to the C language Operator Precedence the operation && is supposed to happen before the operation ||. So shouldn't the result be 2 1 ? (a = 2, b = 1)
when OR'ing expressions in C, a shortcut is taken, I.E. as soon as an expression is evaluated to TRUE, the rest of the OR'd expressions are not evaluated
The first expression a evaluates to TRUE, so all the rest of the expressions are not evaluated, so a is never incremented
When applying the operator precedence rules, the expression is equivalent to:
int b = a || ((a | a) && a++);
The evaluation or the operands to || and && is performed from left to right and shortcut evaluation prevents evaluating the right operand if the left operand can determine the result: since a is non zero, a || anything evaluates to 1 without evaluating the right operand, hence bypassing the a++ side effect.
Therefore both a and b have value 1 and the program prints 1 1.
Conversely, if you had written int b = (a || ((a | a)) && a++;, the left operand of && would have value 1, so the right operand need to be evaluated. a++ evaluates to 1 but increments a, so b have final value 1 and a is set to 2, producing your expected result.
The confusion comes from equating operator precedence with order of evaluation. These are two separate notions: operator precedence determines the order in which to apply the operators, but does not determine the order of evaluation of their operands.
Only four operators have a specified order of evaluation of their operands: &&, ||, ? : and , and the first 2 may skip evaluation of one, depending on the value of the other operand and the third only evaluates the first and only one among the second and third operands. For other operators, the order of evaluation of the operands is unspecified, and it may differ from one compiler to another, one expression to another or even one run to another, although unlikely.
When I try to put a || (a | a) into a parenthesis. The result was as you expected.
So I guess that when C compiler executes an OR operator and it get a True value to the OR, the execution will finish immediately.
In your case, when the compiler executed the a || (a | a) (1 || something) operation. Value of b will be declared to 1 right away and a++ operator won't be execute.
I'm reviewing material on C. I'm not sure why the answer is 12 and 32. In the first printf(), I thought that %d = 2 (i), %d = 2 (j), \n = new line. Can anyone explain this?
#include <stdio.h>
int main(void) {
int i,j;
i=2 && (j=2);
printf("%d%d\n",i,j);
(i=3) || (j=3);
printf("%d%d\n",i,j);
}
For the first expression, i=2 && (j=2); is implicitly evaluated as i = (2 && (j = 2)); because the assignment operator = has lower precedence compared to the logical operators. In the first condition, 2 has the truth value of true, and logical AND && causes all conditions to be evaluated, meaning j = 2 is also evaluated, assigning 2 to j and returning 2 which evaluates to true. So now the actual expression to be evaluated is i = 2 && 2; which is true, or in C's terms, 1. So, i is assigned 1, and the first output is 12.
For the second expression (i=3) || (j=3);, the logical OR || is used, and short circuiting ensures that if the first condition evaluates to true, the overall expression is true and so the second condition is not evaluated. So after i = 3 is evaluated, i is assigned 3 and the entire expression is true, so j = 3 is not evaluated. And so the second output is 32.
Based on precedences, the first expression is evaluated as
i = (2 && (j=2));
So i=1 (true) and j=2. That is why the first output is 12.
The second expression is a logical OR of two assignments.
(i=3) || (j=3);
But since the first evaluation from left is "true" (i=3) the second evaluation is not done. That is why value of j remains 2 and the second output is 32 (not 33).
The reason 12 is printed instead of 22 is because i is assigned the value of 2 && (j=2). First j gets assigned to 2. Then (j=2) returns 2. After that 2 && 2 is evaluated to true, and it returns true. This is because && checks if both sides are true, and 2 is interpreted as true. Since both sides are true, it returns true which is 1.
The || does not evaluate right hand side if left is evaluated to true. The reason is that it is not necessary. It should evaluate to true if at least one of the operators evaluates to true, and i=3 evaluates to 3 which is interpreted as true. That's why 32 is printed instead of 33.
The feature that it does not evaluate right operand if left evaluates to true can be used to do this:
foo() || printf("foo() returned false\n");
And similar for &&, but this operator does not evaluate right operand if left evaluates to false.
foo() && printf("foo() returned true\n");
Note that I'm not suggesting that these tricks should be used. I'm just using them as an example of how || and && may skip evaluating the right operand depending on the value on the left.
I am doing review questions which ask me "What is the output of the following," and I am having some trouble understanding something about this function:
int a = 1, b = 1, c = -1;
c = --a && b++;
printf("%d %d %d", a, b, c);
The output is 010. My question is about line 2, c = --a && b++. How is this line processed, and how does it work/change the values? And if it were c = --a || b++? From my understanding I thought the output would be 020.
The key concept to understanding the result is short-circuit evaluation of Boolean operators (&& and ||) -- if, after evaluating the left-hand side of a Boolean operator, the value of the right-hand side cannot affect the overall result, then it will not be evaluated and any side-effects it would produce will not happen.
In the first case, since --a evaluates to 0 (=false) the second part of ... && ... is not evaluated, since "false AND anything" will always be false. Specifically, b++ is never executed, and so its value remains 1 in the output.
In the case of --a || b++, the value of the whole expression cannot be determined by the left-hand side ("false OR something" can still be true) so the b++ is evaluated (and it's side-effect, incrementing b, happens).
The other concept needed to fully understand the results is the difference between pre- and post-increment/decrement operators. If the -- or ++ appears before the variable (as in --a) then the variable is decremented or incremented first and new value is used to evaluate the whole expression. If the -- or ++ appears after the variable (as in b++) then the current value of the variable is used to evaluate the expression and the increment/decrement happens after this has happened.
It should be noted that expressions that try to combine two or more instances of --/++ of the same variable (e.g. a++ + ++a) are quite likely to invoke undefined behaviour -- the result may vary by platform, compiler, compiler and even the time of day.
In the expression c = --a && b++, a gets decreased and returned. Now the second argument of the expression --a && b++ is not evaluated because of short circuit evaluation---once we see that --a==0 we already know that the expression will be 0 regardless of what is the other argument---, so b remains unchanged.
Decreased a is 0 and b remains 1.
The output is, as you suggest, 0 1 0.
Regarding the second question, if you write c = --a || b++, the variable a again goes to zero but the expression can still evaluate to true---we must thus evaluate the second part as well, thus executing b++ which returns 1 and increases b. In this case the output would be 0 2 1, because c is assigned the value of 0 || 1 which is 1.
In short, read up on
pre- and post-increment in C and C++ and on
short circuit evaluation.
The thing you need to focus on here first is the properties of prefix and postfix operators and their differences.
For Postfix increment and decrement operators, C11, chapter §6.5.2.4, (emphasis mine)
The result of the postfix ++ operator is the value of the operand. As a side effect, the
value of the operand object is incremented [...] The postfix -- operator is analogous to the postfix ++ operator, except that the value of
the operand is decremented.
For Prefix increment and decrement operators, C11, chapter §6.5.3.1, (emphasis mine)
The value of the operand of the prefix ++ operator is incremented. The result is the new
value of the operand after incrementation. [...] The prefix -- operator is analogous to the prefix ++ operator, except that the value of the
operand is decremented.
Now, there comes the property of the Logical AND (&&) operator. From chapter §6.5.13, (again, emphasis mine)
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 equal to 0, the second
operand is not evaluated. [...]
So, in your case,
int a = 1, b = 1, c = -1;
c = --a && b++;
gets evaluated as
c = 0 && .....; // done..., a is decremented to 0,
// so, LHS of && is 0, RHS is not evaluated,
// b remains 1
// and finally, C gets 0.
On the other hand, if logical OR (||) would have been used, then, as per the property, mentioned in chapter §6.5.14
[...] 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, for the case
int a = 1, b = 1, c = -1;
c = --a || b++;
it will be evaluated as
c = 0 || 1; //yes, b's value will be used, and then incremented.
So,
printf("%d %d %d", a, b, c);
will be
0 2 1
b++ is simply never executed because --a evaluates to false in an and condition.
The right side of the and is never executed because not needed. Hence b is never incremented and hence the output you did not expect.
c = --a && b++;
In this first --a is evaulated and a becomes 0 , as soon as 1 operand of && is false , b++ is not evaluated , therefore ,b remains 1 and c becomes 0.
The line :
c = --a && b++;
decreases a to 0, so the statement 0 && anything else results to 0. This is why a and c result to 0, as it seems you have understood.
Now let's see the part you don't get. When a is evaluated to 0, the right part of && does not need to be evaluated, as no matter what the value of the right part will be calculated to be, the result will be 0. This means that b++ will not be evaluated and therefore b will retain its initial value. This is why you see the value 1 instead of 2, and consequently the output 0 1 0 instead of 0 2 0.
--a : mean you decrease a before do the line. b++: increase b after do the line. so that c ( at that time ) = 0+1 =1; then: a =0, b = 2, c =1; OK
I expected b to be 3.
is this an undefined behavior?
or the result could be predicted?
but i thought b would be 3.
and c would be 2.
the output i got is 1 2 1
please explain
#include<stdio.h>
int main()
{
int a = 0;
int b = 1;
int c = (a++ >b++ )? a++ : b++;
printf("%d %d %d",a,b,c);
return 0;
}
That's what I get, and I agree it's guaranteed to be that. There is a sequence point after evaluating the first operand (the condition) before going to the second or third operand. So it goes like this:
(a++ >b++ )
evaluates to:
0 > 1
which is 0.
After that, a is 1 and b is 2.
Since it was false:
b++
is evaluated. The result is 2 (which is assigned to c), and afterwards b is 3.
If that's the exact code, your compiler is buggy. It's not even a question of order. Even if the third operand were evaluated before the first (which would be wrong), b should still be 3.
I am using GCC 4.6.3, but the result will be the same in all standards-compliant compilers.
It's defined behavior, there's a sequence point between the first operand of ?: and second or third one.
So after evaluating a++ < b++, a = 1 and b = 2. Then the third operand gets selected. Thus c gets assigned b++. So c = 2 and then b = 3.
The C11 standard says:
6.5.15 Conditional operator
The first operand is evaluated; there is a sequence point between its
evaluation and the evaluation of the second or third operand
(whichever is evaluated).
Consider this code:
int a = 5;
if (a == 5 || a == 10)
doSomething();
In this case a is 5 so the first condition is true. Will the program check if the second condition is true or it will start executing doSomething() immediately after it makes sure that a is really 5?
It will start executing immediately. This is known as short-circuit evaluation.
http://en.wikipedia.org/wiki/Short-circuit_evaluation
The second condition won't be checked. C short-circuits logical evaluations, so as soon as the truth or falsehood of the condition can be determined it stops.
Note that given the code as posted, the compiler might not even generate code to perform the first comparison as it can determine at compile time that the condition is satisfied and no intervening code could alter the value of a.
Share and enjoy.
int a = 5;
if (a == 5 || a == 10)
doSomething();
in this example the left operand operand of || is evaluated to 1 so the right operand will not evaluated.
The compiler is required to not evaluate the right operand of || operator when the left operand is evaluated to 1.
When it comes to the logical operations, the compiler will stop evaluating the expression as soon as its finds the truth or falsehood of the expression.
The truth-table for logical or (||) operation is as follows:
A B A||B A&&B
0 0 0 0
0 1 1 0
1 0 1 0
1 1 1 1
So for an expression like a == 5 || a == 10, when a is equal to 5, the expression will be evaluated to true when the compiler sees a == 5 part. So irrespective of whether the rest of the expression is evaluated to true or false, due to the logical or (||) operator (refer the above truth-table), this expression will be evaluated to true. So the compiler will discard executing the rest of the expression.
Any decent compiler will not even check the first condition since at compile time it knows at once that it should invoke your method. (but of course all comments about short circuit hold true - but not here ;-)