Luke Wu said:
No, the compiler views it according to the associativity rules(right to
left) as this:
(a = (b = c)) <=== right to left associativity
Yes, that's how it's parsed.
No, that doesn't impose requirements on the order things are actually
done. All that's required is that these happen:
- c is evaluated to get a value
- The value of c, converted appropriately, is stored in b
- The value stored in b, converted appropriately, is stored in a.
Which order they happen in depends only on dependencies between them,
and the store to a only depends on the value stored in b being calculated
(and even there the compiler may be able to determine what it is without
actually calculating it - see my example below), not on it actually
being stored in b.
If they all have the same types, any self-respecting optimizing compiler
will load the value once and store it twice without doing anything else
between the stores. In the simple case it will assign to b first, but
there's no reason why it needs to, and (especially if they're not both
local variables) there might be good reasons not to.
If different types (and, therefore, conversions) are involved, it's even
easier to come up with a perfectly reasonable way for the store to a to
happen first, or for both stores to happen at the same time.
Consider, f'rexample, a word-addressed machine where char * and void *
(as "byte pointers") have a different representation than other pointers.
(Such machines do exist, and as far as I know have C implementations;
Chris Torek likes using one of them as an example.)
If a and c are, say, int * and b is a void *, then the most sensible
way to execute "a=b=c" is:
--------
load r1,c ;Load value to be stored
load a1,a ;Load location to store word pointer
store r1,a1 ;Store word pointer
shl r1,2 ;Convert word pointer to byte pointer
load a1,b ;Load location to store byte pointer
store r1,a1 ;Store byte pointer
--------
Since the word pointer -> byte pointer -> word pointer conversion ends
up being a no-op, this reordering gives the exact same results as if
the double conversion had been done, and is therefore just as valid.
For the case where they're all the same type, consider
Consider also (all ints):
a + b + c
the value in a is equal to -b, the value in both b and c is almost
INT_MAX, so will over flow occur?
If the value of a+b can be added to c without overflowing, the generated
code has to act as if no overflow occurred, since the value being added
to c is the value of a+b.
If the compiler knows that, f'rexample, the machine uses 2s-complement
with silent wraparound on overflow, it's free to generate code that
computes b+c and then adds a to that, since it knows that the result
will be the same whether something overflows or not.
The only requirement is that the correct values get stored in the
correct places before the next sequence point. Operations without
dependencies, or operations that can commute with each other, can be
(and, with optimizing compilers, usually are) done in any order the
compiler likes, no matter what the code says.
dave