I'm not very familiar with the C++ standard, but in the C standard a load from a different union member than the last store isn't undefined behavior, it's unspecified behavior. That's a big difference. So long as the store doesn't generate a trap representation (and most architectures don't have such representations anymore) when reinterpreted as the new type, then you can rely on the behavior, it's just that you'll need to refer to compiler documentation to understand the values reliably produced.
Moreover, there are additional guarantees when reading through char types, as well as unsigned types, so depending on the precise code things may very well be totally well defined.
C doesn't disallow type punning. The gotchas mostly have to do with visibility to the compiler, otherwise the compiler may reorder loads and stores. The safest way to do type punning is through union members as the standard makes additional guarantees that restrict the types of optimizations a compiler can make.
Moreover, there are additional guarantees when reading through char types, as well as unsigned types, so depending on the precise code things may very well be totally well defined.
C doesn't disallow type punning. The gotchas mostly have to do with visibility to the compiler, otherwise the compiler may reorder loads and stores. The safest way to do type punning is through union members as the standard makes additional guarantees that restrict the types of optimizations a compiler can make.