4 ms·
> In ye olden times, the C standard was considered guidelines rather than a ruleset, undefined behavior was closer to implementation-defined behavior than dark
by rstuart4133 2y ago
> In ye olden times, the C standard was considered guidelines rather than a ruleset, undefined behavior was closer to implementation-defined behavior than dark magic, and optimizers were stupid enough to make that distinction irrelevant. On a majority of platforms, dereferencing a null pointer compiled and behaved exactly like dereferencing a value at address 0.
Let me unpack that for you. Old compilers didn't recognise undefined behaviour, and so compiled the code that triggered undefined behaviour in exactly the same way they compiled all other code. The result was implementation defined, as the article says.
Modern compilers can recognise undefined behaviour. When they recognise it they don't warn the programmer "hey, you are doing something non-portable here". Instead they may take advantage of it in any way they damned well please. Most of those ways will be contrary to what the programmer is expecting, consequently yielding a buggy program.
But not in all circumstances. The icing on the cake is some undefined behaviour (like dereferencing null pointers) is tolerated (ie treated in the old way), and some not. In fact most large C programs will rely on undefined behaviour of some sort, such as what happens when integers overflow or signed is converted to unsigned.
Despite that, what is acceptable undefined behaviour and what is not isn't defined by the standard, or anywhere else really. So the behaviour of most large C programs is it legally allowed to to change if you use a different compiler, a different version of the same compiler, or just different optimisation flags. Consequently most C programs depend on the compiler writers do the same thing with some undefined behaviour, despite there being no guarantees that will happen.
This state of affairs, which is to say having a language standard that doesn't standardise major features of the language, is apparently considered perfectly acceptable by the C standards committee.
- ahartmetz 2y agoI see at least two possible reasons why it happened: 1. "Don't do something counterproductive" or "Don't get your priorities wrong" do not usually need to be said explicitly, 2. Standards "culture" values precision so much that they'd balk at writing fuzzy things like "Do typical null pointer things when trying to deref a null pointer". Then later 3. "But we implemented it that way for the benchmarks, can't regress there!"
- uecker 2y agoNote that in most scenarios compiler do not "recognize UB" and then don't tell you about it. Instead, they do not know whether there will be UB or not at run-time and simply assume that you know what you are doing. I also like to point out that not all modern compilers behave the same way. GCC will (in the case it is clear there will be a null pointer dereference) compile it into a trap, while clang will cause chaos: https://godbolt.org/z/M158Gvnc4 https://godbolt.org/z/M158Gvnc4 Both have sanitizers to detect this scenario.
- rstuart4133 2y ago> Note that in most scenarios compiler do not "recognize UB" and then don't tell you about it. Instead, they do not know whether there will be UB or not at run-time and simply assume that you know what you are doing. The point is the old K&R era compilers did that 100% of the time, whereas the current crop uses UB as an excuse to generate some random behaviour some percentage of the time. Programmers can't tell you when that happens because it varies wildly with compilers, versions of compilers and flags passed. Perhaps you are right in saying it's "most scenarios" - but unless you are a compiler writer I'm not sure who you would know, and even then it only applies to the compiler you are familiar with.