What is the modern, correct way to do type punning in C++?

First of all, you assume that sizeof(long) == sizeof(int) == sizeof(float). This is not always true, and totally unspecified (platform dependent). Actually, this is true on my Windows using clang-cl and wrong on my Linux using the same 64-bit machine. Different compilers on the same OS/machine can give different results. A static assert is at … Read more

Portable data reinterpretation

Solution 2 is portable – type punning through unions has always been legal in C99, and it was made explicit with TC3, which added the following footnote to section 6.5.2.3: If the member used to access the contents of a union object is not the same as the member last used to store a value … Read more

Is reinterpret_cast type punning actually undefined behavior?

I believe your misunderstanding lies here: This reads to me as an explicit statement that the result of reinterpret_cast<T&>(v) is an lvalue reference to an object of type T, to which access is clearly “through a glvalue of” “the dynamic type of the object”. [basic.lval]/8 is a bit misleading because it talks about the dynamic … Read more

union ‘punning’ structs w/ “common initial sequence”: Why does C (99+), but not C++, stipulate a ‘visible declaration of the union type’?

I’ve found my way through the labyrinth to some great sources on this, and I think I’ve got a pretty comprehensive summary of it. I’m posting this as an answer because it seems to explain both the (IMO very misguided) intention of the C clause and the fact that C++ does not inherit it. This … Read more

Aliasing T* with char* is allowed. Is it also allowed the other way around?

Some of your code is questionable due to the pointer conversions involved. Keep in mind that in those instances reinterpret_cast<T*>(e) has the semantics of static_cast<T*>(static_cast<void*>(e)) because the types that are involved are standard-layout. (I would in fact recommend that you always use static_cast via cv void* when dealing with storage.) A close reading of the … Read more

What’s a proper way of type-punning a float to an int and vice-versa?

Forget casts. Use memcpy. float xhalf = 0.5f*x; uint32_t i; assert(sizeof(x) == sizeof(i)); std::memcpy(&i, &x, sizeof(i)); i = 0x5f375a86 – (i>>1); std::memcpy(&x, &i, sizeof(i)); x = x*(1.5f – xhalf*x*x); return x; The original code tries to initialize the int32_t by first accessing the float object through an int32_t pointer, which is where the rules are … Read more

Purpose of Unions in C and C++

The purpose of unions is rather obvious, but for some reason people miss it quite often. The purpose of union is to save memory by using the same memory region for storing different objects at different times. That’s it. It is like a room in a hotel. Different people live in it for non-overlapping periods … Read more

Unions and type-punning

To re-iterate, type-punning through unions is perfectly fine in C (but not in C++). In contrast, using pointer casts to do so violates C99 strict aliasing and is problematic because different types may have different alignment requirements and you could raise a SIGBUS if you do it wrong. With unions, this is never a problem. … Read more