3 ms·
> UB means there are absolutely no rules regarding what happens. I will acknowledge that the standard says this, but the original post said "you're not suppose
by Kamq 3y ago
> UB means there are absolutely no rules regarding what happens.
I will acknowledge that the standard says this, but the original post said "you're not supposed to do that ever".
Those are not the same thing.
- dale_glass 3y agoThey are. First, because the compiler isn't bound to any promise. If in version 2.0, you can still use memory immediately after freeing it, version 2.0.1 is perfectly free to make the program misbehave. No consistency has been promised. Second, because per the linked article, compilers treat UB in a particular, weird way. Compilers assume you will not invoke it. Hence this example: #include <stdio.h> int main() { for(int i; i < 10; i++) { printf("%d\n", i); } return 0; } Which a real compiler compiles to this: #include <stdio.h> int main() { return 0; } Why? Because usage of an uninitialized variable is UB. UB is something a programmer doesn't intend to invoke. Therefore the compiler concludes "(undefined)i < 10" never happens. Therefore the loop never runs. Therefore the loop can be removed. UB is not just non-portable, modern compilers treat it as a weird, radioactive state they avoid touching.
- Kamq 3y agoI acknowledge all of your points, and agree to everything you've said. Except for the actual point that the compiler not being bound by any promise means you should never do it. If you want to walk it back to "it's very rare that intentionally using UB is a good idea", I could agree with that. But never is a bridge too far.
- dale_glass 3y ago> Except for the actual point that the compiler not being bound by any promise means you should never do it. > If you want to walk it back to "it's very rare that intentionally using UB is a good idea", I could agree with that. But never is a bridge too far. No. The point of writing code is having the computer do the thing you want. If there's no predictable outcome, then it should never be done. BTW, the outcome can also change depending on optimization level. So this can produce code that works in debug mode and breaks in release mode or viceversa. If there's something I don't ever look forward to is a program that's impossible to debug because debugging changes its behavior.
- Kamq 3y ago> The point of writing code is having the computer do the thing you want. Correct. We definitely agree here. Most importantly, we didn't talk about the specification at all in this sentence. The behavior of the computer is what we care about. And UB only exists in the spec, it's not a thing compilers or computers do (it's an absence of specification about what a theoretical compiler would do). > If there's no predictable outcome, then it should never be done. I also agree here. But, with a particular compiler there is almost always a predictable outcome. > BTW, the outcome can also change depending on optimization level. And here, I think you're actually being too conservative. It can change with much more than just the optimization level. If you're doing intentional UB, you'd want to freeze not only your optimization level, but your entire flag set. And changing any of them could lead to months of debugging and fixing things. This trade-off is almost never worth it. But I maintain that the "almost" belongs in that sentence.
- dale_glass 3y ago> I also agree here. But, with a particular compiler there is almost always a predictable outcome. It's potentially variable depending on other things involved, like system headers you might be including, and system updates. > And here, I think you're actually being too conservative. It can change with much more than just the optimization level. If you're doing intentional UB, you'd want to freeze not only your optimization level, but your entire flag set. And changing any of them could lead to months of debugging and fixing things. Well, isn't that a pleasant prospect there. As somebody who reviews PRs my answer to anything along those lines is: over my dead body. > This trade-off is almost never worth it. But I maintain that the "almost" belongs in that sentence. Okay, I'll grant you it's a fine idea if you want to sabotage a project and drive the other people to madness. Which if you're being paid for it may be actually illegal. Otherwise, I still go with "never". If you need to do something this bizarrely specific, if it's worth doing at all, then it's time to do it in assembly, where you can do any random weird thing you want without the compiler getting in your way.
- Kamq 3y agoI mean, just as an example, if you're working on a weird embedded system (so you can't really change compilers) where certain parts that are UB in the spec are guaranteed to have certain behavior? Additionally assuming function pointers are the same size as void *, which isn't guaranteed by the spec, when you're working on platform specific code. Although they may start optimizing that one at some point.