5 ms·
> Clang and GCC are reaching for any optimization they can get. Undefined Behavior may be hostile and dangerous, but it's legal. So don't let your code become a
by throw0101b 2y ago
> Clang and GCC are reaching for any optimization they can get. Undefined Behavior may be hostile and dangerous, but it's legal. So don't let your code become a casualty.
Perhaps we need a -Wundefined-behaviour so that compilers print out messages when they use those type of 'tricks'. If you see them you can then choose to adjust your code in a way that it follows defined path(s) of the standard(s) in question.
- Uvix 2y agoIsn't that what -fsanitize=undefined does?
- MaulingMonkey 2y ago`-fsanitize=undefined` enables some runtime warnings/checks, `-Wundefined-behaviour` would presumably enable some kind of compile time warnings/checks.
- saagarjha 2y agoYou’ll have far too many messages.
- tedunangst 2y agoDo you want a warning on every for (int i = 0; i < n; i++) loop?
- saurik 2y agoYes: that loop is miserable and we should upgrade it to use size_t (and preferably ++i), at which point the undefined behavior required to make that abomination fast wouldn't matter anymore.
- JonChesterfield 2y agoWhy would you prefer to preincrement an integer? Too much time around C++ iterators?
- saurik 2y agoI mean, why would you ever prefer to post-increment an integer whose prior value you didn't need? Not enough time studying iterators to make that distinction obvious, perhaps? Regardless, the context here is that we should stop relying so much on the compiler to paper over differences in code that don't by the user anything except a form of quaint familiarity with old code: the i++ relies on the optimizer knowing it doesn't have to keep the prior value, while ++i doesn't, and yet somehow I guess you are enamored with i++ despite it being exactly the same characters to type, merely in a different order. Stop using int, stop using post-increment, and sure: maybe even stop using < when you semantically want != (though I explicitly didn't go there because that isn't--as far as I know--going to affect the performance with a dumber compiler).
- JonChesterfield 2y agoPattern matching is a big thing in programming. Not in C++, as ++i executes arbitrary code found an unbounded distance from the programmer (so ++i vs i++ might be a very important distinction) but in other languages it helps a lot. for (int i=0, j=0; i < N && j < M; i+=2, j++) i++ looks like i+=1 so fits better in loops iterating over multiple things. Also that int says "these values don't overflow" very concisely and the more modern cleverer C++ using iterator facades probably fails to communicate that idea to anyone. edit: amused to note on checking for typos that I wrote that with < instead of != which violates your other recommendation, which is one I'm in favour of in theory but apparently don't write out by default.
- karatinversion 2y agoI always thought the problem with this was that the compilers do loads of these optimisations in very mundane ways. Eg if I have a #define FOO 17 void bar(int x, int y) { if (x + y >= FOO) { //do stuff } } void baz(int x) { bar(x, FOO); } the compiler can inline the call to bar in baz, and then optimise the condition to (x>=0)… because signed integer overflow is undefined, so can’t happen, so the two conditions are equivalent. The countless messages about optimisations like that would swamp ones about real dangerous optimisations.
- im3w1l 2y agoHow much is actually gained by removing checks like these, and is it worth the cost? Can we find a safer approach to making the code fast?
- somat 2y agoI have to admit I don't really understand the logic behind how compiler writers got to the point where they were able to interpret "undefined behavior" as "will not happen" My understanding is that undefined behavior is in the spec because the various physical machines that C could compile to would each do something different. So to avoid stepping on toes the spec basically punted and said we are not going to define what happens. Originally this was fine. the C compiler would dutifully generate the machine instructions and the machine would execute them returning the result. The wrench was thrown into the works when we started getting optimizing compilers. I would argue the correct interpretation of "undefined behavior" in the face of a optimizing compiler is "unknown" but then it would sort of behave like the sql NULL(each unknown is different from every other unknown) and act as an optimization fence. When you have to ask the machine what the result of this operation is, it is hard to optimize around it ahead of time. So my best guess as to why they decided to read "undefined" as "can not happen" is that this is the interpretation they can best optimize for. And nobody really pushed back because what the hell does "undefined" mean anyway? My read is that if the spec wanted to say "can not happen" the spec would have said "can not happen"
- karatinversion 2y ago
- userbinator 2y agoOr better yet, perhaps they should just do the sane thing instead of being a hostile pedantic smartass. Undefined shouldn't mean "whatever", it should be an opportunity to consider what makes the most sense.
- amelius 2y agoBut then you have to write a standard.
- lmm 2y agoYou actually don't. Plenty of languages and compilers manage to be less programmer-hostile without a written standard. Unfortunately GCC/Clang have prioritised getting higher numbers on benchmarks.
- favorited 2y ago> Unfortunately GCC/Clang have prioritised getting higher numbers on benchmarks. Because that's what people actually want. There's no untapped market for a C compiler that doesn't aggressively optimize. The closest you'll get is projects selectively disabling certain optimizations, like how the Linux kernel builds with `-fno-strict-aliasing`.
- lmm 2y ago> There's no untapped market for a C compiler that doesn't aggressively optimize. There probably isn't now, because people who want sanity have moved on from C.I do think that years ago a different path was possible. > The closest you'll get is projects selectively disabling certain optimizations, like how the Linux kernel builds with `-fno-strict-aliasing`. Linux also does `-fno-delete-null-pointer-checks` and probably others. I don't think they have a principled way of deciding, rather whenever an aggressive optimization causes a terrible bug they disable that particular one and leave the rest on.
- userbinator 2y ago
- circuit10 2y agoIt’s not always possible to predict in advance when undefined behaviour can happen
- pjc50 2y agoLast time I suggested this it was unpopular. https://news.ycombinator.com/item?id=40787276 https://news.ycombinator.com/item?id=40787276 (even for the relatively high-profile and easy-sounding "detect if the compiler has deleted a line of code in a way which alters observable behavior of the program"!)
- throwaway2037 2y agoDo any static analysis tools (commercial or open source) already do this now?