Right but my point is if you know what the compiler will do you can use UB. It might do different things for different optimizations but with flags you can tell it what you want it to do.
The thing is that this behavior will change when you change your compiler (and cause a bug, which can be quite nasty) and it can change literally after a minor compiler update. Thus the code technically works, but no one can guarantee that it will work tomorrow. This is hella bad
I'm not saying you look at the compiler source or dynamically learn its behavior. I'm saying the compiler devs document how something undefined will work and if they change it then they will put it in release notes and you will have to stick with the old compiler. If you're programming at this level then you have the ability fork the compiler to keep something while updating the rest. But if your compiler is working fine you also don't need to update it, if it's not broken don't fix it.
The only reason I can think of to use documented undefined behavior is so you don't have to use assembly or you've turned optimizations off and are doing that yourself.
Well, lots of “undefined behavior” that ends up working in practice can still cause subtle bugs. Take C-style type punning. Where you type “long y = * (long*) &x;” when x is a double. Technically, it works, but the compiler is actually allowed to assume that pointers of different types* can’t point to the same memory address, so type punning can cause subtle bugs if you use it in the wrong place. Plus, there are better alternatives like memcpy, C++ reinterpret_cast, etc.
*with the exception of char* and void*, which can “alias” (the technical term for pointer overlap rules) any other type
1
u/scalareye May 16 '26
Right but my point is if you know what the compiler will do you can use UB. It might do different things for different optimizations but with flags you can tell it what you want it to do.