I don't think the C standard's inclusion of implementation / undefined behavior is due to what OP calls a "documentation standard", documenting a variety og behavior already codified into various implementations...
Rather, it seems that the C standard tried (& succeeded) from the beginning in making it easy to implement a compiler that generated good code, even to the extent of including register allocation hints to the compiler. This also appears to be why the short/int/long types are defined the way they are - not as types with specific ranges, but rather only that long >= int >= short. This allowed a given implementation to map int to whatever was most appropriate to the target CPU, be it 8-, 16- or 32-bit.
In this vein, wanting to be fast on all targets, I don't think C wanted to assume the presence of an MMU or any hardware required to efficiently detect NULL pointers, so instead just left this as an instance of implementation defined behavior.
C isn't alone in this regard - AFAIK many languages only define the behavior of correct programs and leave the behavior of buggy ones as implementation defined.
Rather, it seems that the C standard tried (& succeeded) from the beginning in making it easy to implement a compiler that generated good code, even to the extent of including register allocation hints to the compiler. This also appears to be why the short/int/long types are defined the way they are - not as types with specific ranges, but rather only that long >= int >= short. This allowed a given implementation to map int to whatever was most appropriate to the target CPU, be it 8-, 16- or 32-bit.
In this vein, wanting to be fast on all targets, I don't think C wanted to assume the presence of an MMU or any hardware required to efficiently detect NULL pointers, so instead just left this as an instance of implementation defined behavior.
C isn't alone in this regard - AFAIK many languages only define the behavior of correct programs and leave the behavior of buggy ones as implementation defined.