Which would be calculated first? - c

Only 3 days while learning C. Noticed this in the book:
int main() {
int x = 10, y = 15;
if (x % 2 == y % 3) {
printf("Which one x%2 or y%3 calculated first");
}
}
My question is in if condition. Question is which expression is calculated first, x%3 or y%3?

The short answer is: C does not specify which of x % 2 and y % 3 is computed first, and since there is no side effect in either sub-expression, it does not matter.
The long answer is: Actually, looking at the generated code on Godbolt Compiler Explorer, the expression may be evaluated at compile time and none of these are computed at runtime.
Very few C operators have a specified order of evaluation:
the comma operator ,
the logical and && and logical or || as well as the ternary operator ? : (they actually only evaluate their second or third operand if the first has a specific truth value).
function arguments are evaluated before the function is called, but their relative order of evaluation is unspecified.

I is a tricky question and it was very popular during the interviews some time ago.
If I make it this example a bit less trivial and avoid optimisations:
int comapare(int x, int y) {
int result;
if (result = (x % 2 == y % 3)) {
printf("Which one x%%2 or y%%3 calculated first");
}
return result;
}
The order of evaluation of this particular is undetermined as only logical operators are guaranteed from the left to the right and evaluate the smallest number of operands needed to determine the result of the expression. Operator == along with all other comparison operators is not the logical operator.
Most interviewed candidates answered that it will be evaluated from the left to the right as it is the logical operation.

It's a good question Gaurav. Always have that inquisitive mind as that's how you can attain true learning.
As suggested in the comments, this question relates to Operator Precedence and Associativity.
Here you can get an idea in general.
Here, it's more specific to your question. As you can see there (point# 3), for % operator, it is from Left-to-right.
It is important to distinguish here between how equality == works versus the assignment operator = as the later works from right-to-left. As mentioned in that link, for the assignment operators like =, the expression a=b=c is parsed as a=(b=c), and not as (a=b)=c because of right-to-left associativity.
Hope this will clear your doubts!
Additional clarifications:
Based on subsequent discussions in the comment section, I feel it necessary to remove some of the confusions.
Confusion about operator associativity and order of evaluation:
If two operators are of same precedence, Associativity of operators determines the order in which they execute. The associativity of == is left to right, i.e, the expression on the left is executed first and moves toward the right. So answer to the question of which expression is calculated first in the equation x % 2 == y % 3, the answer would be like this:
1. evaluation of x % 2.
2. evaluation of y % 3.
3. evaluation of ==
Do compilers strictly follow this rule?
Not necessarily. The compilers are free to evaluate such expressions in any order, if they can guarantee a consistent result. Only the sequential-evaluation (,), logical-AND (&&), logical-OR (||), conditional-expression (? :), and function-call operators constitute sequence points and therefore guarantee a particular order of evaluation for their operands.
Authentic reference: https://msdn.microsoft.com/en-us/library/2bxt6kc4.aspx

Related

Does && force evaluation of relational, arithmetic operators on left of it before evaluation of higher ranking operators on right (C99)? [duplicate]

This question already has answers here:
What is short-circuit evaluation in C?
(3 answers)
Closed 2 years ago.
Consider the following code:
int y, x; y = 2; x = 0;
x!=0&&y/x>5
My lecturer's textbook on C provides a table for "Precedence hierarchy for the arithmetic, relational, and logical operators" using this table to evaluate the operators in the above expression I get the following precedence:
(1) is /, therefore, do y/x first
(2) is >, (3) is !=, (4) is &&.
If I evaluate the above code using this precedence hierarchy, then the first subexpr to be evaluated is:
y / x
which is
2 / 0, or undefined...
The given answer is 0.
Later on, the textbook also states that, per the ANSI C standard, the operand on the left of && will always be evaluated first, and only if this is 0 will the operand on the right be evaluated.
Does this mean that whenever a logical and (&&) (or a logical or (||) for that matter) appears in an expression along with arithmetic and relational operators, that effectively I need to separate the terms of the overall expression into two groups - terms on the left, and terms on the right, of the &&, and ONLY THEN begin applying the "Precedence hierarchy for the arithmetic, relational, and logical operators" to the operators contained in the overall 'left hand operand'?
This would result in the above expression being evaluated as:
(x!=0) && (y/x>5)
starting with the left operand, (x!=0), which is (0!=0), which is false, so 0, and thus no further evaluation takes place.
--
If this is the case, why does the && operator appear so low down the hierarchy of precedence if its inclusion in an expression dictates what must be done first?
In this case, you're encountering something called "short circuit evaluation". Think of your condition if (x != 0 && y / x > 5) as if (somethingIsTrue && somethingIsTrue). In order for that to be true, it must become if (true && true). In short circuit evaluation, it sees that x !=0 is false and immediately stops evaluating there because no matter what comes after it, the first thing is false so it can never be true.
And yes, to your point, you can sort of think of it as splitting the expressions into groups between the && and || statements. Each of those individual expressions gets evaluated as true or false, and then just look at it as a bunch of true or false statements in between && and || statements. So, for something like if (blah1 && blah2 || blah3), no matter what blah1, blah2, and blah3 are, they will all get evaluated to true or false. And then you just see how it plays out like if (true && true || false) or something like that.
And on a side note, don't bang your head against a wall trying to memorize precedence rules. Most of them are intuitive and you'll get the hang of the correct way of doing things as you program more.
The precedence of operator makes clear how your expression x!=0&&y/x>5 is to be interpreted. Think about it as setting braces. So the compiler would read your expression as (x!=0) && ((y/x)>5). Note here that the operators with the highest precedence are getting braces first, the ones with lower precedence are getting braces later.
Now the evaluation takes place. Evaluation is done from outer to inner. The outmost operator is the one with the lowest priority, the &&. It has two operands, the left one and the right one. Now the standard says that the left one is to be evaluated first. If it is false, then the && returns false (shortcut). If it is true, then the right operand needs to be evaluated.
The good thing about this guaranteed evaluation order is that you can now safely write for example if (x!=0 && y/x>10) or if (pointer!=NULL && pointer->data != 3).
Precedence and associativity only say how to structure an expression. They do not say how to evaluate it. Consider x+y*z. Were it not for precedence, we could structure this expression as (x+y)*z, shown on the left, or x+(y*z), shown on the right.
* +
/ \ / \
+ z x *
/ \ / \
x y y z
Precedence tells us to use the latter. But we can still evaluate x, y, and z in any order. Suppose x, y, and z are actually function calls with side effects; perhaps they print “x”, “y”, and “z”. If we evaluate z and remember its result, then evaluate y, then multiply them, then evaluate x, and then add, we will get the same result as if we evaluate x, then y, then z, then multiply, then add.
Both of these orders of evaluation use the same expression structure, the latter one. So the precedence that gave us the expression structure did not tell us how to evaluate the expression. (Almost—the structure does compel us to get the result of the multiplication before we can use it in the addition.)
The && and || operators have a property beyond precedence: They have a rule that their left operand is evaluated first, and the right operand is evaluated only if the left operand does not determine the result.
Digging deeper, there are two computations associated with some expressions. Each expression has its main effect: to produce a value, such as the sum, product, or logical AND of its operands. Some expressions also have side effects, such as incrementing an object (in x++) or writing output (putchar('c')). The side effect does not have to be done at the same time as the main effect. Generally, it can be done any time during the full expression it is in, and it can be before, during, or after the main effect.
The ordering property of the && and || operators extends to side effects: They require all side effects of their left operand be completed before any part of the right operand is evaluated.

Short circuit and operator precedence in C

I know that logical operators in C follow short circuiting but my doubt is that are short circuiting and operator precedence rules not opposing each other. See the below example :
#include<stdio.h>
int main()
{
int a;
int b=5;
a=0 && --b;
printf("%d %d",a,b);
return 0;
}
According to the precedence rules, the highest precedence is of the prefix operator. So --b should be evaluated first and then the && and at last result will be assigned to a. So expected output should be 0 4. But in this case the second operand of && never actually executes and result comes out to be 0 5.
Why precedence rules are not being applied here. Are logical operators exempted from precedence rules? If yes, what other operators show such behavior? And what is the logic behind this behavior?
You're conflating two related but different topics: operator precedence and order of evaluation.
The operator precedence rules dictate how various operators are grouped together. In the case of this expression:
a=0 && --b;
The operators are grouped like this:
a = (0 && (--b));
This has no effect however on which order the operands are evaluated in. The && operator in particular dictates that the left operand is evaluated first, and if it evaluates to 0 the right operand is not evaluated.
So in this case the left side of && which is 0 is evaluated, and because it is 0 the right side which is --b is not evaluated, so b is not incremented.
Here's another example of the difference between operator precedence and order of evaluation.
int val()
{
static x = 2;
x *= 2;
return x;
}
int main()
{
int result = val() + (5 * val());
printf("%d\n", result);
return 0;
}
What will the above program print? As it turns out, there are two possibilities, and both are valid.
In this expression:
val() + (5 * val())
There are no operators that have any type of short circuit behavior. So the compiler is free to evaluate the individual operands of both + and * in any order.
If the first instance of val() is evaluated first, the result will be 4 + ( 5 * 8) == 44. If the second instance of val() is evaluated first, the result will be 8 + (5 * 4) == 28. Again, both are valid since the operands may be evaluated in any order.
Precedence affects how ambiguous expressions are parsed. When there are multiple ways to interpret an expression with several operators, precedence tells us which interpretation is correct. Think of precedence as a mechanism to figure out where the implied parentheses are.
For example in the statement in question there are two valid ways to parse it. If = had higher precedence than && it could be read as:
(a = 0) && --b;
But since && has higher precedence, it's actually interpreted as:
a = (0 && --b);
(Note: Your code's formatting suggests it's the first. Be careful not to mislead!)
Evaluation order is different from precedence. They're related, but independent concepts. After precedence is used to determine the correct parsing of an expression, evaluation order tells us the order to evaluate the operands in. Is it left to right? Right to left? Simultaneous? Unspecified?
For the most part evaluation order is left unspecified. Operators like + and * and << have no defined evaluation order. The compiler is allowed to do whatever it likes, and the programmer must not write code that depends on any particular order. a + b could evaluate a then b, or b then a, or it could even interweave their evaluations.
= and &&, among others, are exceptions. = is always evaluated right to left, and && is left to right with short circuiting.
Here's how evaluation proceeds step-by-step for our statement:
a = (0 && --b), = evaluated right to left
0 && --b, && evaluated left to right with short circuiting
0, evaluates false which triggers short circuiting and cancels the next step
--b, not evaluated due to short circuiting
result is 0
a, variable reference evaluated
a = 0, assignment occurs and overall result is 0
You said that there is no specific order for + and *, but this table shows the order to be left to right. Why so?
The last column of that table is associativity. Associativity breaks precedence ties when we use the same operator twice, or when we use operators with the same precedence.
For example, how should we read a / b / c. Is it:
(a / b) / c, or
a / (b / c)?
According to the table / has left-to-right associativity, so it's the first.
What about chained assignments like foo = bar = baz? Now, assignment has right-to-left associativity, so the correct parsing is foo = (bar = baz).
If this all gets confusing, focus on one simple rule of thumb:
"Precedence and associativity are independent from order of evaluation."
Operator precedence doesn't necessarily tell that an expression gets executed first, it just means that the expression is parsed such that the result of the higher-precedence operation is used in the lower-precedence operation and not the other way around. The actual expressions only get evaluated if they need to!
operator && 's order of evaluation is left to right.
= has lower precedence, in fact only ooperator , has lower precedence than =.
So the expresssion will read a = (0 && --b) being 0 evaluated first given the mentioned order of evaluation.
Since 0 evaluates to false, there is no need to evaluate the second part of the expression because false && true is false, given the first part of the expression is false, the expression will always be false.
If you had || operator the second part of the expression would have to be evaluated.
Operator precedence is not all that plays in the game. There is also order of evaluation. And that mandates that a=0 is evaluated first (evaluation order is from left to right), and then right part after the && is not evaluated at all.
That is how C works.

Beginner in need of a simple explanation of the difference between order of evaluation and precedence/associativity

I am reading the end of the 2nd chapter of K&R and I'm having some difficulty understanding two specific unrelated example lines of code (which follow) along with commentary of them in the book:
x = f() + g();
a[i] = i++;
FIRST LINE - I have no trouble understanding that the standard does not specify the order of evaluation for the + operator, and that therefore it is unspecified whether f() or g() evaluates first (and that is why I think the question isn't a duplicate). My confusion stems from the fact that if we look up the C operator precedence chart it cites function calls as of highest precedence with left-to-right associativity. Now doesn't that mean that f() has to be called/evaluated before g()? Obviously not, but I don't know what I am missing.
SECOND LINE - Again the similar conundrum regarding whether the array is indexed to the initial value of i or the incremented value. However, again the operator precedence chart cites array subscripting as of highest precedence with left-to-right associativity. Therefore wouldn't array subscripting be the first thing to be evaluated causing the array to be subscripted to the initial value of i and removing any unambiguity? Obviously not, and I'm missing something.
I do understand that compilers have the freedom to decide when side effects happen in an expression (between sequence points of course) and that that may cause undefined behaviour if the variable in question is used again in the same expression, however in the examples above it seems that any ambiguity is cleared by function calls and array subscripting having highest precedence and defined left-to-right associativity, so I fail to see the ambiguity.
I have a feeling that I have some fundamental misconception about the concepts of associativity, operator precedence and order of evaluation, but I can't point my finger on what it is, and similar questions/answers on this topic were out of my league to understand thoroughly at this point.
FIRST LINE
The left-to-right associativity means that an expression such as f()()() is evaluated as ((f())())(). The associativity of the function call operator () says nothing about its relationship with other operators such as +.
(Note that associativity only really makes sense for nestable infix operators such as binary +, %, or ,. For operators such as function call or the unary ones, associativity is rather pointless in general.)
SECOND LINE
Operator precedence affects parsing, not order of evaluation. The fact that [] has higher precedence than = means that the expression is parsed as (a[i]) = (i++). It says very little about evaluation order; a[i] and i++ must both be evaluated before the assignment, but nothing is said about their order with respect to each other.
To hopefully clear up confusion:
Associativity controls parsing and tells you whether a + b + c is parsed as (a + b) + c (left-to-right) or as a + (b + c) (right-to-left).
Precedence also controls parsing and tells you whether a + b * c is parsed as (a + b) * c (+ has higher precedence than *) or as a + (b * c) (* has higher precedence than +).
Order of evaluation controls which values need to be evaluated in which order. Parts of it can follow from associativity or precedence (an operand must be evaluated before it's used), but it's seldom fully defined by them.
It's not really meaningful to say that function calls have left-to-right associativity, and even if it were meaningful, this would only apply to exotic combinations where two function-call operators were being applied right next to each other. It wouldn't say anything about two separate function calls on either side of a + operator.
Precedence and associativity don't help us at all in the expression a[i] = i++. There simply is no rule that says precisely when within an expression i++ stores the new result back into i, meaning that there is no rule to tell us whether the a[i] part uses the old or the new value. That's why this expression is undefined.
Precedence tells you what happens when you have two different operators that might apply. In a + b * c, does the + or the * apply first? In *p++, does the * or the ++ apply first? Precedence answers these questions.
Associativity tells you what happens when you have two of the same operators that might apply (generally, a string of the same operators in a row). In a + b + c, which + applies first? That's what associativity answers.
But the answers to these questions (that is, the answers supplied by the precedence and associativity rules) apply rather narrowly. They tell you which of the two operators you were wondering about apply first, but they do not tell you much of anything about the bigger expression, or about the smaller subexpressions "underneath" the operators you were wondering about. (For example, if I wrote (a - b) + (c - d) * (e - f), there's no rule to say which of the subtractions happens first.)
The bottom line is that precedence and associativity do not fully determine order of evaluation. Let's say that again in a slightly different way: precedence and associativity partially determine the order of evaluation in certain expressions, but they do not fully determine the order of evaluation in all expressions.
In C, some aspects of the order of evaluation are unspecified, and some are undefined. (This is by contrast to, as I understand it, Java, where all aspects of evaluation order are defined.)
See also this answer which, although it's about a different question, explains the same points in more detail.
Precedence and associativity matter when an expression has more than one operator.
Associativity doesn't matter with addition, because as you may remember from grade school math, addition is commutative and associative -- there's no difference between (a + b) + c, a + (b + c), or (b + c) + a (but see the Note at the end of my answer).
But consider subtraction. If you write
100 - 50 - 5
it matters whether you treat this as
(100 - 50) - 5 = 45
or
100 - (50 - 5) = 55
Left associativity means that the first interpretation will be used.
Precedence comes into play when you have different operators, e.g.
10 * 20 + 5
Since * has higher precedence than +, this is treated like
(10 * 20) + 5 = 205
rather than
10 * (20 + 5) = 250
Finally, order of evaluation is only noticeable when there are side effects or other dependencies between the sub-expressions. If you write
x = f() - g() - h()
and these functions each print something, the language doesn't specify the order in which the output will occur. Associativity doesn't change this. Even though the results will be subtracted in left-to-right order, it could call them in a different order, save the results somewhere, and then subtract them in the correct order. E.g. it could act as if you'd written:
temp_h = h();
temp_f = f();
temp_g = g();
x = (temp_f - temp_g) - temp_h;
Any reordering of the first 3 lines would be allowed as an interpretation.
Note
Note that in some cases, computer arithmetic is not exactly like real arithmetic. Numbers in computers generally have limited range or precision, so there can be anomalous results (e.g. overflow if the result of addition is too large). This could cause different results depending on the order of operations even with operators that are theoretically associative, e.g. mathematically the following two expressions are equivalent:
x + y - z = (x + y) - z
y - z + x = (y - z) + x
But if x + y overflows, the results can be different. Use explicit parentheses to override the default associativity if necessary to avoid a problem like this.
Regarding your first question:
x = f() + g();
The left-to-right associativity relates to operators at the same level that are directly grouped together. For example:
x = a + b - c;
Here the + and - operators have the same precedence level, so a + b is first evaluated, then a + b - c.
For an example more related to yours, imagine a function that returns a function pointer. You could then do something like this:
x()();
In this case, the function x must be called first, then the function pointer returned by x is called.
For the second:
a[i] = i++;
The side effect of the postincrement operator is not guaranteed to occur until the next sequence point. Because there are no sequence points in this expression, the i on the left side may be evaluated before or after the side effect of ++. This invokes undefined behavior due to both reading and writing a variable without a sequence point.
FIRST LINE - Associativity is not relevant here. Associativity only really comes into play when you have a sequence of operators with the same precedence. Let's take the expression x + y - z. The additive operators + and - are left-associative, so that sequence is parsed as (x + y) - z - IOW, the result of z is subtracted from the result of x + y.
THIS DOES NOT MEAN that any of x, y, or z have to be evaluated in any particular order. It does not mean that x + y must be evaluated before z. It only means that the result of x + y must be known before the result of z is subtracted from it.
Regarding x = f() + g(), all that matters is that the results of f() and g() are known before they can be added together - it does not mean that f() must be evaluated before g(). And again, associativity has no effect here.
SECOND LINE - This statement invokes undefined behavior precisely because the order of operations is unspecified (strictly speaking, the expressions a[i] and i++ are unsequenced with respect to each other). You cannot both update an object (i++) and use its value in a computation (a[i]) in the same expression without an intervening sequence point. The result will not be consistent or predictable from build to build (it doesn't even have to be consistent from run to run of the same build). Expressions like a[i] = i++ (or a[i++] = i) and x = x++ all have undefined behavior, and the result can be quite literally anything.
Note that the &&, ||, ?:, and comma operators do force left-to-right evaluation and introduce sequence points, so an expression like
i++ && a[i]
is well-defined - i++ will be evaluated first and its side effect will be applied before a[i] is evaluated.
Precedence and associativity fall out of the language grammar - for example, the grammar for the additive operators + and - is
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
IOW, an additive-expression can produce a single multiplicative-expression, or it can produce another additive-expression followed by an additive operator followed by a multiplicative-expression. Let's see how this plays out with x + y - z:
x -- additive-expression ---------+
|
+ +-- additive-expression --+
| |
y -- multiplicative-expression ---+ |
+-- additive-expression
- |
|
z -- multiplicative-expression -----------------------------+
You can see that x + y is grouped together into an additive-expression first, and then that expression is grouped with z to form another additive-expression.

Operator associativity with 'postfix decrement' and 'logical AND' operators in c

Disclaimer: I don't code like this, I'm just trying to understand how the c language works!!!!
The output is 12.
This expression (a-- == 10 && a-- == 9) evaluates left-to-right, and a is still 10 at a-- == 10 but a is 9 for a-- == 9.
1) Is there a clear rule as to when post-increment evaluate? From this example it seems it evaluates prior to the && but after the ==. Is that because the && logical operator makes a-- == 10 a complete expression, so a is updated after it executes?
2) Also for c/c++, certain operators such as prefix decrement occur right to left so a == --a first decrements a to 9 and then compares 9 == 9. Is there a reason for why c/c++ is designed this way? I know for Java, it's the opposite (it's evaluates left to right).
#include <stdio.h>
int main() {
int a = 10;
if (a-- == 10 && a-- == 9)
printf("1");
a = 10;
if (a == --a)
printf("2");
return 0;
}
The logical && operator contains a sequence point between the evaluation of the first and second operand. Part of this is that any side effect (such as that performed by the -- operator) as part of the left side is complete before the right side is evaluated.
This is detailed in section 6.5.13p4 of the C standard regarding the logical AND operator:
Unlike the bitwise binary & 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
equal to 0, the second operand is not evaluated.
In the case of this expression:
(a-- == 10 && a-- == 9)
The current value of a (10) is first compared for equality against 10. This is true, so the right side is then evaluated, but not before the side effect of decrementing a that was done on the left side. Then, the current value of a (now 9) is compared for equality against 9. This is also true, so the whole expression evaluates to true. Before the next statement is executed, the side effect of decrementing a that was done on the right side is done.
This expression however:
if (a == --a)
Involves reading and writing a in the same expression without a sequence point. This invokes undefined behavior.
This expression (a-- == 10 && a-- == 9) evaluates left-to-right,
Yes, mostly, but only because && is special.
and a is still 10 at a-- == 10
Yes, because a-- yields the old value.
but a is 9 for a-- == 9.
Yes, because the sequence point at && guarantees the update to a's value is complete before the RHS is evaluated.
1) Is there a clear rule as to when post-increment evaluate?
The best answer, I think, is "no". The side effects due to ++ and -- are completed at some point prior to the next sequence point, but beyond that, you can't say. For well-defined expressions, it doesn't matter when the side effects are completed. If an expression is sensitive to when the side effect is completed, that usually means the expression is undefined.
From this example it seems it evaluates prior to the && but after the ==. Is that because the && logical operator makes a-- == 10 a complete expression, so a is updated after it executes?
Basically yes.
2) Also for c/c++, certain operators such as prefix decrement occur right to left
Careful. I'm not sure what you mean, but whatever it is, I'm almost certain it's not true.
so a == --a first decrements a to 9 and then compares 9 == 9.
No, a == --a is undefined. There's no telling what it does.
Is there a reason for why c/c++ is designed this way?
Yes.
I know for Java, it's the opposite (it's evaluates left to right).
Yes, Java is different.
Here are some guidelines to help you understand the evaluation of C expressions:
Learn the rules of operator precedence and associativity. For "simple" expressions, those rules tell you virtually everything you need to know about an expression's evaluation. Given a + b * c, b is multiplied by c and then the product added to a, because of the higher precedence of * over +. Given a + b + c, a is added to b and then the sum added to c, because+ associates from left to right.
With the exception of associativity (as mentioned in point 1), try not to use the words "left to right" or "right to left" evaluation at all. C has nothing like left to right or right to left evaluation. (Obviously Java is different.)
Where it gets tricky is side effects. (When I said "'simple' expressions" in point 1, I basically meant "expressions without side effects".) Side effects include (a) function calls, (b) assignments with =, (c) assignments with +=, -=, etc., and of course (d) increments/decrements with ++ and --. (If it matters when you fetch from a variable, which is typically only the case for variables qualified as volatile, we could add (e) fetches from volatile variables to the list.) In general, you can not tell when side effects happen. Try not to care. As long as you don't care (as long as your program is insensitive to the order in which side effects matter), it doesn't matter. But if your program is sensitive, it's probably undefined. (See more under points 4 and 5 below.)
You must never ever have two side effects in the same expression which attempt to alter the same variable. (Examples: i = i++, a++ + a++.) If you do, the expression is undefined.
With one class of exceptions, you must never ever have a side effect which attempts to alter a variable which is also being used elsewhere in the same expression. (Example: a == --a.) If you do, the expression is undefined. The exception is when the value accessed is being used to compute the value to be stored, as in i = i + 1.
With "logical and" operator (a-- == 10 && a-- == 9) is well-formed expression (without undefined behavior as it is in a++ + a++).
C standard says about "logical and"/"logical or" operators:
guarantees left-to-right evaluation; there is a sequence point after
the evaluation of the first operand.
So that, all side effects of the first subexpression a-- == 10 are complete before the second subexpression a-- == 9 evaluation.
a is 9 before evaluation of second subexpression.
The underlying problem is that the postfix unary operator has both a return value (the starting value of the variable) and a side effect (incrementing the variable). While the value has to be calculated in order, it is explicit in the C++ specs that the sequencing of any side effect relative to the rest of the operators in a statement is undefined, as long as it happens before the full expression completes. This allows compilers (and optimizers) to do what they want, including evaluating them differently on different expressions in the same program.
From the C++20 code spec (C++ 2020 draft N4849 is where I got this from):
Every value computation and side effect associated with a full-expression is
sequenced before every value computation and side effect associated with the
next full-expression to be evaluated.
[6.9.1 9, p.72]
If a side effect on a memory location is unsequenced
relative to either another side effect on the same memory location or
a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined. [6.9.1 10, p.72]
So, in case you haven't gotten it from other answers:
No, there is no defined order for a postfix operator. However, in your case (a-- == 10 && a-- == 9) has defined behavior because the && enforces that the left side must be evaluated before the right side. It will always return true, and at the end, a==8. Other operators or functions such as (a-- > a--) could get a lot of weird behavior, including a==9 at the end because both prefix operators store the original value of a(10) and decrement that value to 9 and store it back to a.
Not only is the side-effect of setting a=a-1 (in the prefix operator) unsequenced with the rest of this expression, the evaluation of the operands of == is also unsequenced. This expression could:
Evaluate a(10), then evaluate --a(9), then == (false), then set a=9.
Evaluate --a(9), then a(10), then set a=9, then evaluate == (false).
Evaluate --a(9) the set a=9, then evaluate a(9), then evaluate == (true)
Yes, it is very confusing. As a general rule (which I think you already know): Do not set a variable more than once in the same statement, or use it and set it in the same statement. You have no idea what the compiler is going to do with it, especially if this is code that will be published open source, so someone might compile it differently than you did.
Side note:
I've seen so many responses to questions about the undefined behavior of postfix operators that complain that this "undefined behavior" only ever occurs in the toy examples presented in the questions. This really annoys me, because it can and does happen. Here is a real example of how the behavior can change that I had actually happen to me in my legacy code base.
result[ctr]=source[ctr++];
result[ctr++]=(another calculated value without ctr in it);
In Visual Studio, under C++14, this evaluated so that result had every other value of source in even indexes and had the calculated values in the odd indexes. For example, for ctr=0, it would store source[0], copy the stored value to result[0], then increment ctr, then set result[1] to the calculated value, then increment ctr. (Yes, there was a reason for wanting that result.)
We updated to C++20, and this line started breaking. We ended up with a bad array, because it would store source[0], then increment ctr, then copy the stored value to result[1], then set result[1] to the calculated value, then increment ctr. It was only setting the odd indexes in result, first from source then overwriting the source value with the calculated value. All the odd indexes of result stayed zero (our original initialization value).
Ugh.

Operator Precedence in C language

Can someone tell me what is happening behind the scenes here?
main()
{
int z, x=5, y=-10, a=4, b=2;
z = ++x - --y*b/a;
printf("%d", z);
}
Strange way to write code man...anyway...I try...
Resolves ++x and --y
Resolves multiplications and divisions
Resolves the remaining (plus and minus)
So...
z= 6 - (-11) * 2 /4
z= 6 - (-22) / 4
z= 6 - (-5) (the result is truncated due to (-22) / 4 being an integer division)
I get z= 11.
The variable z is declared int so it becomes 11.
I suggest to write this line in a simpler way!! Oh...sorry for my english...
This expression
z=++x - --y*b/a;
is evaluated in the following order in an abstract machine
Variable x is incremented and becomes equal to 6.
Variable y is decremented and becomes equal to -11.
Variable y is multiplied by variable b and the result is equal to -22.
The result of the preceding operation is divided by variable a and as there is used the integer arithmetic the result is equal to -5.
At last there is subtraction of the result from variable x and the result is equal to 11.
Run the program and be sure whether I am correct.
Take into account that a particular implementation may evaluate the operands in a different order provided that the result will be the same as I described for the abstract machine.
According to the C Standard (5.1.2.3 Program execution)
4 In the abstract machine, all expressions are evaluated as specified
by the semantics. An actual implementation need not evaluate part of
an expression if it can deduce that its value is not used and that no
needed side effects are produced (including any caused by calling a
function or accessing a volatile object).
First of all, please note the difference between operator precedence and order of evaluation of sub expressions.
Operator precedence dictates which operations that have to be done and evaluated, before the result of those operations are used together with the rest of the expression. This works similarly to mathematical precedence: 1 + 1 * 2 is guaranteed to give result 3, not 4. Because * has higher precedence than +.
Order of evaluation equals the actual order of execution, and is unspecified behavior, meaning that a compiler is free to execute the various sub expressions in any order it likes, in order to produce the fastest possible code. And we can't know the order. Most operators in C involve unspecified order of evaluation (except some special cases like && || ?: ,).
For example the in the case of x = y() + z(), we can know that + operation will get executed before =, but we can't tell which of the functions y and z that will get executed first. It may or may not matter to the result, depending on what the functions do.
Then to the expression in the question:
Operator precedence dictates that the two operations ++x and --y must be evaluated before the other operations, since the prefix unary operators have highest precedence of those present in the expression.
Which sub expression of ++x and --y*b/a that is evaluated first is not specified. We can't tell the order of execution (and --y*b/a does in turn contain several sub expressions). At any rate, the order of evaluation does not matter here, it will not affect the result.
The increments/decrements ++x and --y will take place before the results of those operations are used together with the rest of the expression.
Operator precedence then dictates that the operations involving * and / must be evaluated next. These operators have the same precedence, but they belong to the multiplicative operators group, which has left-to-right associativity, meaning that --y*b/a is guaranteed to evaluate --y*b first. After that, the result will get divided by a.
So the whole right-most sub expression is equivalent to ( (--y) * b ) / a.
Next, operator precedence dictates that - has higher precedence than =. So the result of the sub expressions ++x is subtracted by the result of the sub expression --y*b/a .
And finally the result is assigned to z, since = had the lowest precedence.
EDIT
Btw, the proper way to write the same, and get the very same machine code, is this:
++x;
--y;
z = x - (y*b)/a;
Apart from giving reduced readability, the ++ and -- operators are dangerous to mix with other operators since they contain a side effect. Having more than one side effect per expression could easily lead to various forms of unsequenced processing, which is always a bug, possibly severe. See this for examples.
"Operator precedence" means the rules for deciding what the operands are of each operator. In your case, using parentheses to indicate:
z=++x - --y*b/a;
is equivalent to:
z = ((++x) - (((--y) * b) / a));
Now, this line of code and the following printf statement has the same observable behaviour as the code:
z = (x + 1) - ((y - 1) * b / a);
printf("%d\n", z);
x = x + 1;
y = y - 1;
C is defined in terms of observable behaviour (which approximately means the output generated by the program; you can see a technical definition by reading the C standard). Any two programs which would produce the same observable behaviour according to the standard , are considered to be exactly equivalent.
This is sometimes called the "as-if rule" and it is this rule that allows optimization to occur.
Addressing points raised by some of the other answers:
There are rules surrounding exactly what ++ and -- do. Specifically, the effects of incremeting x and decrementing y are defined so that the writing back of the increment and decrement could happen at any time during the execution of z=++x - --y*b/a; . They could be in either order, or simultaneous; the writing of the decrement could be either before or after the computation of (y-1) * b, and so on.
In some different code examples, we would use these rules to work out the observable behaviour of the program, and it would not be quite so flexible as this particular program.
But in this code example, since nothing else depends on the timing of those increments and decrements, it turns out that we can even hoist them past the printf, according to the "as-if rule".

Resources