3 ms·
The semantics of "restrict", which made it into C99, inherently require the anything-goes interpretation of UB to have the keyword make any sense. These means y
by jcranmer 4y ago
The semantics of "restrict", which made it into C99, inherently require the anything-goes interpretation of UB to have the keyword make any sense. These means your "faulty" definition of undefined behavior is at least 23 years old. If you dig a little deeper, it has to be even older. The semantics of unions were changed in C99 so as to make type punning via unions no longer UB--which at least implies that people were thinking about the optimization effects of UB even earlier.
The other thing to note was that if UB were "just" about portability to "weird" machines... why did the C committee choose to make it undefined instead of implementation-defined? The specification already has a tool that gives compilers flexibility for weird architectures; not using that tool suggests that the committee didn't want to require the compiler to do something "reasonable."
- electroly 4y agoYour question seems to be rhetorical and assumes that I know the answer, but I don't. Why did they choose to make all this stuff UB instead of implementation-defined? I don't really understand why we have UB at all instead of all of that stuff being implementation-defined. Other languages have far fewer things that they consider UB, and that seems better to me. Why was having a large swath of UB considered better?
- andi999 4y agoI think historically the idea behind UB was to allow to write a compliant compiler (for different platforms) as easily as possible. (so to decrease the burden on the compiler writer). This has worked. Why they kept this approach? I dont know.
- jcranmer 4y agoThere are a few reasons to make things UB. One of the big reasons is--drumroll--to enable compiler optimizations. The other big reason is some variation on the problem that actually coming up with reasonable semantics is difficult to impossible, and often one of the factors that makes such semantics difficult is again because of compiler optimizations. I think there's a big misconception here that the use of UB to drive optimizations is somehow a perversion of the original design for C, but the evidence strongly points away from that. In particular, strict aliasing rules don't really make sense unless you're going to use them to afford optimization opportunities, and those were present as far back as C89. I will additionally point out that any C-like language is going to have a large kernel of necessarily UB to permit any optimization whatsoever (namely, UB in relation to memory unsafety) [1]. The things in C where people most complain about UB--namely signed integer overflow and strict aliasing--also happen to be the ones where there's no good reason to interpret C89's decision to make them UB instead of something lesser as anything other than letting compilers optimize them because they're UB. Even if it seems to be gratuitous (and I would personally argue that it is), it is very much intentional. [1] Yes, even Rust makes this UB.
- xscott 4y agoI've thought a lot about the restrict keyword since a month ago when you and I argued about this in the context of intentionally adding UB to Rust. I think you're wrong to conclude that UB was some kind of goal for "restrict" in C. As I remember it, there was a bit of envy in how Fortran compilers could make a few optimizations that C compilers could not. (Even now, some of the old-time Fortran advocates still trot this out as a reason Fortran is better) So C needed a way to say, "this function is more like Fortran now, go ahead and re-order the reads and writes if it helps". Thus "restrict" was born as a promise from the programmer to the compiler. The keyword mostly makes sense from that point of view, but of course there are devils in the details as shown in Ralf's article. I haven't seen the mission statement, but there seems to be some agreement that the intent of the standards committee was to "codify existing practice" rather than define things on first principles or something. I'm sympathetic to the standard saying, "it's undefined to break your promise on this new feature we gave you". As for why to make things like signed overflow undefined vs implementation defined, we could argue about it. If you've got a link to something more than speculation about that choice, I'd like to read it. My opinion shouldn't be terribly valuable to anyone. > not using that tool suggests that the committee didn't want to require the compiler to do something "reasonable." I believe it's a completely valid interpretation to treat undefined behavior as implementation defined. Maybe the whole point was, "Let them do what they want. The users can pick a different compiler if they want." At this point, assuming the future standards mission is still to "codify existing practice", they'll probably keep listening to the compiler writers and programmers who prefer niche optimizations over sanity. Btw, you should think about whether these optimizations are really that valuable. You're paying a cost, are you getting a benefit? Take a computationally intensive program you care about and recompile it with -frwapv. Don't just look at the assembly, measure the run time. Outside of some contrived example you don't really care about, I doubt you'll see much difference. And even if you do have an example you care about, I'm guessing it could be fixed by changing a 32 bit signed int to use a 64 bit array index.
- jcranmer 4y ago> As for why to make things like signed overflow undefined vs implementation defined, we could argue about it. If you've got a link to something more than speculation about that choice, I'd like to read it. My opinion shouldn't be terribly valuable to anyone. I'm (slowly) working on a "In Defense of UB" blog post, and I'm going to see if I can track down some old C committee members who might be able to offer more than speculation here. But I can't guarantee it, this is about discussions that happened well over 3 decades ago, and there's a good chance that recollections of details from that time are imperfect or just plain missing.