For example there were programs 30-40 years ago that relied on exact stack layouts. These days everybody would agree they are completely broken.
The issue of course is that it is extremely hard to write programs that have no UB. It would be nice for compilers to have an option to automatically introduce assetions whenever they rely on some UB-derived axiom, basically as a sort of lightweight sanitizer.
In fact if we had sanitizers 30-40 years ago probably things would be better today.
Modifying a value from a different thread without synchronization is UB. The compiler assumes this does not happen in order to e.g. move things into registers. Could you elaborate how (and how often) you would like to have this kind of UB-derived axiom ("this value remains the same from here to there") checked with assertions?
https://www.parasoft.com/products/parasoft-insure/
21 years later it is still an uphill battle to adopt such technology in C and C++ projects.
"Although the first edition of K&R described most of the rules that brought C's type structure to its present form, many programs written in the older, more relaxed style persisted, and so did compilers that tolerated it. To encourage people to pay more attention to the official language rules, to detect legal but suspicious constructions, and to help find interface mismatches undetectable with simple mechanisms for separate compilation, Steve Johnson adapted his pcc compiler to produce lint [Johnson 79b], which scanned a set of files and remarked on dubious constructions. "
That seems to be a static analysis tool though (which generally have not been great). Did it also inject runtime checks?
And a famous commercial variant of it has been PC-lint from https://www.gimpel.com/.
Being available on open source compilers does little to change the culture, as per latest surveys only 11% of developers care to use any kind of tooling for improving their code quality in C and C++.
At CppCon a couple of years ago, only about 1% of the audience answered positively to Herb Sutters' question.
https://isocpp.org/files/papers/CppDevSurvey-2021-04-summary...
Of course compilers have to make assumptions. The debate is (a) over what assumptions it is proper to make and (b) what are the permissible behaviors. The false dichotomy: either do without any optimizations at all or accept whatever UB gives you, is not a useful approach.
Inferring any propositional statement about the program (eg "this pointer is not null") from the fact that its negation would imply undefined behaviour.
Even if you opt into those (and the projects I've been involved with have), the precedent is established: when new compiler optimizations are introduced with disruptive semantics, they are opt-out, not opt-in — a fail-dangerous failure mode.
> Doesn't that indicate that C programmers indeed want to sacrifice safety for optimizations?
Maybe so. Which is one reason I wouldn't call myself a "C programmer" any more. The demands to program responsibly in C are absurdly high.
Actually, the default for gcc is -O0. You are opting in with -O2 etc.
BCPL was anyway designed to Bootstrap CPL, nothing else.
Yes, that means C without optimizing without UB is slower than Java. Optimizations need some form of reasoning about what's happening. For Java it's optimizing based on guarantees provided by the language (there's no raw pointers that could mess with the things listed above). But C doesn't provide any hard guarantees, so instead it needs to blindly assume that the code will behave sanely.
Also note that for many of the more manageable sources of UB, most compilers provide a choice (-fwrapv, -fno-strict-aliasing, ...). Yet few projects use these options, even when they use other gcc/clang-specific features. Doesn't that indicate that C programmers indeed want to sacrifice safety for optimizations?