Operator Precedence in C language - c

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".

Related

Operators in the C language with the same precedence level?

C programming language documentation Precedence and order of evaluation states:
The direction of evaluation does not affect the results of expressions that include more than one multiplication (*), addition (+), or binary-bitwise (&, |, or ^) operator at the same level. Order of operations is not defined by the language.
What exactly does the above mean (perhaps a code example will help)?
That page is not particularly well-written.
Precedence determines which operators are grouped with which operands in an expression - it does not dictate the order in which subexpressions are evaluated. For example, in the expression a + b * c, the * operator has higher precedence than the + operator, so the expression is parsed as a + (b * c) - the result of a is added to the result of b * c.
However, each of the expressions a, b, and c may be evaluated in any order, even simultaneously (interleaved or in parallel). There’s no requirement that b be evaluated before c or that either must be evaluated before a.
Associativity also affects grouping of operators and operands when you have multiple operators of the same precedence - the expression a + b + c is parsed as (a + b) + c because the + operator (along with the other arithmetic operators) is left-associative. The result of a + b is added to the result of c.
But like with precedence above, this does not control order of evaluation. Again, each of a, b, and c may be evaluated in any order.
The only operators which force left-to-right evaluation of their operands are the &&, ||, ?:, and comma operators.
From the comments:
Because the operands b and c accompany the * (multiplication) operator which has higher precedence than the + (addition operator), then isn't it required (always) that both b and c be evaluated first before a?
The only requirement is that the result of b * c be known before it can be added to the result of a. It doesn’t mean that b * c must be evaluated before a:
t0 <- a
t1 <- b * c
t2 <- t1 + t0
Again, precedence only controls the grouping of operators and operands, not the order in which subexpressions are evaluated.
I assume that what the cited documentation is trying to say is that given the code
a = f1() + f2() + f3();
or
b = f1() * f2() * f3();
we do not know which of the functions f1, f2, or f3 will be called first.
However, it is guaranteed that the result of calling f1 will be added to the result of calling f2, and that this intermediate sum will then be added to the result of calling f3. Similarly for the multiplications involved in computing b. These aspects of the evaluation order are guaranteed due to the left-associativity of addition and multiplication. That is, the results (both the defined and the unspecified aspects) are the same as if the expressions had been written
a = (f1() + f2()) + f3();
and
b = (f1() * f2()) * f3();
Upon reading the cited documentation, however, I fear that I may be wrong. It's possible that the cited documentation is simply wrong, in that it seems to be suggesting that the +, *, &, |, and ^ are somehow an exception to the associativity rules, and that the defined left-associativity is somehow not applicable. That's nonsense, of course: left-associativity is just as real when applied to these operators as it is when applied to, say, - and /.
To explain: If we write
10 - 5 - 2
it is unquestionably equivalent to
(10 - 5) - 2
and therefore results in 3. It is not equivalent to
10 - (5 - 2)
and the result is therefore not 7. Subtraction is not commutative and not associative, so the order you do things in almost always matters.
In real mathematics, of course, addition and multiplication are fully commutative and associative, meaning that you can mix things up almost any which way and still get the same result. But what's not as well known is that computer mathematics are significantly enough different from "real" mathematics that not all of the rules — in particular, commutativity — actually apply.
Consider the operation
-100000000 + 2000000000 + 200000000
If it's evaluated the way I've said it has to be, it's
(-100000000 + 2000000000) + 200000000
which is
1900000000 + 200000000
which is 2100000000, which is fine.
If someone (or some compiler) chose to evaluate it the way I've said it couldn't be evaluated, on the other hand, it might come out as
-100000000 + (2000000000 + 200000000) /* WRONG */
which is
-100000000 + 2200000000
which is... wait a minute. We're in trouble already. 2200000000 is a 32-bit number, which means it can't be properly represented as a positive, 32-bit signed integer.
In other words, this is an example of an expression which, if you evaluate it in the wrong order, can overflow, and theoretically become undefined.
Similar things can happen with floating-point arithmetic. The expression
1.2e-50 * 3.4e300 * 5.6e20
will overflow (exceed the maximum value of a double, which is good up to about 1e307) if the second multiplication wrongly happens first. The expression
2.3e100 * 4.5e-200 * 6.7e-200
will underflow (to zero, exceeding the minimum value of a double) if the second multiplication happens first.
The point I'm trying to make here is that computer addition and multiplication are not quite commutative, meaning that a compiler should not rearrange them. If a compiler does (as the cited documentation seems to, wrongly, claim is possible), you, the programmer, can see results which are significantly and wrongly different from what the C Standard said you were allowed to expect.
I hope this all makes some kind of sense, although in closing, I should perhaps suggest that it's not necessarily as unambiguous and clear-cut as I've made it sound. I believe what I've described (that is, the strict associativity, and non commutativity, of multiplication and addition) is what's formally required by the current C standards, and by IEEE-754. However, I'm not sure they've been required by all versions of the C Standard, and I don't believe they were clearly guaranteed by Ritchie's original definition of C, either. They're not guaranteed by all C compilers, they're not depended upon or cared about by all C programmers, and they're not appreciated by people who write documentation like that cited in this thread.
(Also, for those really interested in fine points, rearranging integer addition as if it were commutative is not quite so wrong — or, at least, it's not visible/detectably wrong — if you know you're compiling for a processor that quietly wraps around on signed integer overflow.)

Unsequenced modification warning [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 2 years ago.
I am reading a book for C and I got stuck into this example.
The author says that the result for this example will be x == 0 and y == 101.
I am fine with the y result,however I really thought that the first thing in the expression will calculate y == y and then will increment y +1.
I compiled the code and got a Warning: unsequenced modification and 1 was stored in x.
What's the reason for this?
int main(void)
{
int x,y=100;
x=y;
x= y == y++;
printf ("%d %d",x,y);
return 0;
}
An expression in C, including a subexpression of another expression, may have two effects:
A main effect: It produces a value to be further used in the containing expression.
A side effect: It modifies an object or file or accesses a volatile object.
In general, the C standard does not say when the side effect occurs. It does not necessarily occur at the same time that the main effect is evaluated.
In x = y == y++;, y++ has the side effect of modifying y. However, y is also used as the left operand of ==. Because the C standard does not say when the side effect will occur, it may occur before, during, or after using the value of y for the left operand.
A rule in the C standard says that if using the value of an object is not sequenced (specified to occur before or after) relative to a modification of that object, the behavior is undefined. Also, if two modifications are unsequenced relative to each other, the behavior is undefined.
An original motivation for this rule is that increment y for y++ could require multiple steps. In a computer with only 16-bit arithmetic, a C implementation might support a 32-bit int by using multiple instructions to get the low 16 bits of y, add 1 to them, remember the carry, store the resulting 16 bits, get the high 16 bits of y, add the carry, and store the resulting bits. If some other code is separately trying to get the value of y, it might get the low 16 bits after the 1 has been added but get the high 16 bits before the carry has been added, and the result could be a value of y that is neither the value before the add (e.g., 0x1ffff) nor the value after the add (e.g.&, 0x20000) but a mix (0x10000). You could say an implementation ought to track operations on objects and keep them separate so this interleaving does not occur. However, that can impose a burden on compilers and interfere with optimization.
In the expression y == y++ the order in which the expressions y and y++ are evaluated is unsequenced or, in simpler terms, the order is not specified.
However, here the result depends on the order in which the expressions are evaluated. Therefore the compiler emits a diagnostic.

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.

Undefined behaviour seems to be contradicting with operator precedence rule in C [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
Consider the following line of code.
int i = 2;
i = i++
The second line of code has been identified as undefined. I know this question has been asked before several times and example being this.
But nowhere could I see the issue of operator precedence being addressed in this issue. It has been clearly mentioned that postfix operator precedes assignment operator.
i = (i++)
So clearly i++ will be evaluated first and this value of i is the assigned to i again.
This looks like this particular undefined behavior is contradicting the precedence rule.
Similar to this is the code:
int i = 2;
i++ * i++;
Here according to operator precedence the code can be written as
int i =2;
(i++) * (i++)
Now we do not know whether the (i++) in LHS or RHS of '*' operator is going to be evaluated first. But either way it is going produce the same result. So how is it undefined?
If we write say:
int p;
p = f1() + f2()
where f1() and f2() are defined functions then obviously it's clear we can't decide whether f1() or f2() is going to be evaluated first as precedence rules does not specify this. But a confusion like this does not seem to arise in the current problem.
Please explain.
I do not understand why this question got a negative vote. I needed a clarity between operator precedence and UB and I have seen no other question addressing it.
What you're looking for is in section 6.5 on Expressions, paragraph 3 of the C standard:
The grouping of operators and operands is indicated by the syntax.
Except as specified later, side effects and value computations of
subexpressions are unsequenced.
This means that the side effect of incrementing (or decrementing) via the ++ or -- operators doesn't necessarily happen immediately when the operator is encountered. The only guarantee is that it happens before the next sequence point.
In the case of i = i++;, there is no sequence point in the evaluation of the operands of = nor in the evaluation of postfix ++. So an implementation is free to perform assigning the current value of i to itself and the side effect of incrementing of i in any order. So i could potentially be either 2 or 3 in your example.
This goes back to paragraph 2:
If a side effect on a scalar object is unsequenced relative
to either a different side effect on the same scalar object
or a value computation using the value of the same scalar
object, the behavior is undefined.
Since i = i++ attempts to update i more than once without a sequence point, it invokes undefined behavior. The result could be 2 or 3, or something else might happen as a result of optimizations for example.
The reason that this is not undefined:
int p;
p = f1() + f2()
Is because a variable is not being updated more than once in a sequence point. It could however be unspecified behavior if both f1 and f2 update the same global variables, since the evaluation order is unspecified.
The problem with using
i = i++
is that the order in which the address of i is accessed to read and write is not specified. As a consequence, at the end of that line, the value of i could be 3 or 2.
When will it be 3?
Evaluate the RHS - 2
Assign it to the LHS. i is now 2.
Increment i. i is now 3.
When will it be 2?
Evaluate the RHS - 2
Increment i. i is now 3.
Assign the result of evaluating the RHS to the LHS. i is now 2.
Of course, if there is a race condition, we don't know what's going to happen.
But nowhere could I see the issue of operator precedence being addressed in this issue.
Operator precedence only affects how expressions are parsed (which operands are grouped with which operators) - it has no effect on how expressions are evaluated. Operator precedence says that a * b + c should be parsed as (a * b) + c, but it doesn't say that either a or b must be evaluated before c.
Now we do not know whether the (i++) in LHS or RHS of '*' operator is going to be evaluated first. But either way it is going produce the same result. So how is it undefined?
Because the side effect of the ++ operator does not have to be applied immediately after evaluation. Side effects may be deferred until the next sequence point, or they may applied before other operations, or sprinkled throughout. So if i is 2, then i++ * i++ may be evaluated as 2 * 2, or 2 * 3, or 3 * 2, or 2 * 4, or 4 * 4, or something else entirely.
OPERATOR PRECEDENCE DOES NOT RESOLVE UNDEFINED EXPRESSION ISSUES.
Sorry for shouting, but people ask about this all the time. I'm afraid I have to say your research on this question must not have been very thorough, if you didn't see this aspect being discussed.
See for example this essay.
The expression i = i++ tries to assign to object i twice. It's therefore undefined. Period. Precedence doesn't save you.

Pre-increment operation in C

I'm just starting a beginner's guide to games programming tutorial in C. I'm a little confused with the code below.
At main gameOverTick is set to zero, then we have a case when the game is over
case GAME_OVER:
printStatus("GAME OVER!!! The evil DarkLord was defeated");
if (++gameOverTick % 100 == 0){
status = PRINT_GAME_WELCOMESCREEN; // go back to welcome screen
gameOverTick = 0; // reset gameOverTick
}
I would just like to know what role the ++ (pre-inc) operation does on gameOverTick. Does it set gameOverTick to 1 whilst checking the if, or set it to 0 somehow. I know how post-inc ++ works, but this is a new one for me.
Thanks
We've got four answers here and they are all wrong in the same way. Let me make sure this is very clear in your mind: people who tell you that precedence of operators determines the order in which side effects occur as a result of computation of subexpressions are simply wrong. In C, the order in which subexpressions are computed is not controlled by precedence; it is largely undefined. (In C# and Java is is defined not as precedence order but as left-to-right.)
In the specific case here, the value of the ++ operation must be computed before the % happens, but the assignment associated with the ++ operation can happen at any time. In your particular case it doesn't matter when the assignment happens, but it is easy to construct cases where it does matter.
This increases gameOverTick by one before the modulo is calculated and the comparison is done. (A good rule of thumb in C is that unitary operations have tighter binding than binary, and calculations over logic operations.) It guess the purpose of this is to wait 100 loops until it goes hack to the welcome screen, as gameOverTick is only reset if it have gone up to 100.
Most expressions in C have a value; most expressions have a side effect.
Consider the two expressions below
/* a */ i++
/* b */ ++i
The side effect of both expressions is to increase the value of i (that change is only usable after the next sequence point). The value of the first expression is the value i had on the previous sequence point; the value of the second expression is one more than what i had at the previous sequence point.
The code you have written inside parenthesis of if is called an expression, the expression evaluation always follow operator precedence rule, considering the given expression
1.++ operator has highest precedence so '++gameOverTick' is evaluated first as '(gameOverTick = gameOverTick+1)'
2.The next next precedence is for '%' operator so '(gameOverTick+1)%100' is calculated
3.Finally the least precedence operator is '==' hence the obtained result on left side of '==' operator is compared for equality with the right side value.
Example:
-Consider gameOverTick value as 99
-99 is incremented first i.e, 99+1 = 100
-Than the % operation is performed i.e, 100%100 = 0
-Now equality is compared` i.e, 0 == 0 which gives 1
-The evaluation of expression gives 1 hence it is equal to if(1), which indicates a true.
For more on operator precedence you can refer this link
http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm

Resources