int a = 5; a = a++ + ++a; a = ? (2011)
8 points by chai
8 points by chai
well... actually two UBs, thanks to which there are three possible correct answers: 11, 12 and 13.
If undefined behaviour is present, then a could have any value after this runs, the program could crash, it could rm -rf your home directory.
That it is undefined behavior would mean that the edge case isn't called out or handled in the C/C++ specification. If a compiler already have integer addition and post-/pre-incrementing according to the specification, then there isn't an unbounded number of possibilities on how these two features can interact between each other in this edge case. It would be up to the individual compilers to choose how these two features interact, but they couldn't claim that rm -rf is a standards compliant way of doing addition and incrementing at the same time.
An analogy to real life would be that a law didn't specify how it would interact on narrow circumstances that are already covered by another law, and also that we didn't have any courts to adjudicate how this ambiguity should be handled. The handling of such cases would thus differ on a case by case basis, so that two identical cases could be handled differently – but neither would involve making up a third law that never was enacted.
That it is undefined behavior would mean that the edge case isn't called out or handled in the C/C++ specification
That would be unspecified behaviour, not undefined behaviour. Undefined behaviour has a very specific meaning in the C/C++ world, and the compiler is free to more or less do whatever it wants. From the standards:
Undefined behavior: behavior for which this International Standard imposes no requirements.
The compiler can abort, the compiler can assume the line is never reached and therefore optimize it out, the compiler can even make demons fly out of your nose.
In fairness while all of these and more can happen due to UBs compilers don't generally go around looking for UBs in order to perform nefarious deeds they can justify under the UB banner. Rather they will either ignore the UB conditions (because they can) or use it as a constraint (e.g. an unchecked dereference will be used as an assertion of non-nullity, which is then propagated both directions).
In this case, the main benefits a compile will derive is that cross-platform support does not need to bother squaring up evaluation order, and optimisations don't a special case to "see" two writes happening to the same location (similar to memcpy on overlapping locations)
To sum up the two previously described UBs for the a = a++ + ++a equation we get:
My thought process (5+7), while leading to one of the „correct“ results, isn’t even listed there: