When the C standard was written, if the effect of a certain action would vary on different platforms, it would not always be possible for a particular platform to guarantee any particular precise effect, and if there might plausibly exist implementations where the action could trigger a hardware trap whose behavior was outside the control of the C compiler, there was little perceived value in having the Standard say anything about the behavior. Even if there wasn't any significant likelihood of a hardware trap, the possibility of "surprising" behavior was sufficient to brand behavior as Undefined.
Consider for example, unsigned long x,*p; ... *p=(x++);
. If p==&x
, it would not only be possible that *p
might end up holding not only the old value of x
, or a value 1 greater, but if x
was e.g. 0x0000FFFF it might also plausibly end up holding 0x00000000, or 0x0001FFFF. Even if no machine would trigger a hardware trap, I don't think the Standard's authors would have considered "Any lvalue modified more than once will hold Indeterminate Value, and any read of an lvalue in the same expression that writes it in a manner other than allowed herein may yield Indeterminate Value" to be in any way more useful than simply declaring such actions to be Undefined Behavior. Further, from the point of view of the Standard's authors, the failure of the Standard to mandate particular behaviors in cases where some platforms could provide free of charge and others could not was not expected to pose an obstacle to the specification of such behaviors on platforms that could provide them.
In practice, even very loosely-specified behaviors can often be very useful for programs which share the following two requirements with the vast majority of programs written today:
- When given valid input, produce correct output.
- When given invalid input, do not launch nuclear missiles.
Unfortunately, someone came up with the idea that if the C Standard does not mandate the behavior of some action X in a particular situation Y, even if most compilers happen to have behavior which would be adequate for programs seeking to meet the above requirements (e.g. most compilers will generate for the expression p < q
code that will either yield 0 or 1 and have no other side-effects, even when p
and q
identify unrelated objects), then action X should be regarded as an indication to the compiler that the program will never receive any input which would cause situation Y.
The indicated (*p=*p) & (*q=*q)
is intended to represent such a "promise". The logic is that since the Standard wouldn't say anything about what a compiler can do if p==q
, a compiler should assume that the programmer wouldn't mind if the program would launch nuclear missiles in response to any input that could cause the code to be executed when p==q
.
That idea and its consequences are fundamentally antithetical to the very nature and design objectives of C and its use a systems-programming language. Nearly all systems offer some features and guarantees beyond those mandated by the Standard, though the specifics vary from one system to the next. I consider preposterous the idea that the language is better served by redefining x < y
from "I'm willing to accept whatever means of pointer comparison is used by any hardware on which this program is actually going to be run" to "I'm so certain that these two pointers will be related that I would stake my life on it", than it would be by adding a new means of directing the compiler to assume that "x and y are related pointers", but somehow it seems to be becoming accepted.