Can you elaborate on that point? Why was it necessary then, but not still necessary now?
Can you elaborate on that point? Why was it necessary then, but not still necessary now?
I would like to give an example of how supporting both 1s- and 2s-compliment is the source of a specific UB, but I can't take the time to do that right now, regrettably. Similarly, supporting both Big Endian and Little Endian was necessary. As was supporting ASCII, EBCDIC, and probably Fieldata and five level Baudot (looking at you, trigraphs). All of this generality made it hard to say anything useful in some areas, so you end up in some cases just calling it Undefined, since there was no consensus on how it should be defined.
For example, forcing extra code to be inserted, that is, a check (or even a call out to a library), so one unified semantic is followed, and there is no undefined behaviour. Of course, you wouldn't mandate how the semantics are followed.
The problem is, it was very hard for us to accept this kind of solution when we grew up feeling like every cycle counted, so that's what I blame for a lot of the UB we see today in the standard.
This is a very valid justification of implementation defined. Maybe even unspecified. But undefined? How could you justify that?
Even if some platform does not support something at all, and goes bananas whenever you do it (say, signed overflow that traps), what would stopped the standard to say that whether the stuff is undefined or not is platform dependent?
Perhaps the committee didn't anticipate how unreasonable compiler writers turned out to be?
----
The terms unspecified behavior, undefined behavior, and implementation-defined behavior are used to categorize the result of writing programs whose properties the Standard does not, or cannot, completely describe. The goal of adopting this categorization is to allow a certain variety among implementations which permits quality of implementation to be an active force in the marketplace as well as to allow certain popular extensions, without removing the cachet of conformance to the Standard. Appendix F to the Standard catalogs those behaviors which fall into one of these three categories.
Unspecified behavior gives the implementor some latitude in translating programs. This latitude does not extend as far as failing to translate the program.
Undefined behavior gives the implementor license not to catch certain program errors that are difficult to diagnose. It also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior.
Implementation-defined behavior gives an implementor the freedom to choose the appropriate approach, but requires that this choice be explained to the user. Behaviors designated as implementation-defined are generally those in which a user could make meaningful coding decisions based on the implementation definition. Implementors should bear in mind this criterion when deciding how extensive an implementation definition ought to be. As with unspecified behavior, simply failing to translate the source containing the implementation-defined behavior is not an adequate response.