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);
}
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...
++x
and --y
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:
++x
and --y
must be evaluated before the other operations, since the prefix unary operators have highest precedence of those present in the expression.++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.++x
and --y
will take place before the results of those operations are used together with the rest of the expression.*
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
. ( (--y) * b ) / a
.-
has higher precedence than =
. So the result of the sub expressions ++x
is subtracted by the result of the sub expression --y*b/a
.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".