Search code examples
c++unionstype-punning

what really mean by Type Punning is an application of union?


what really means by type-punning in the union? for example

#include <iostream>

using namespace std;

union test {
    int x;
    float y;
};

int main()
{
    test t;
    t.y = 1.5;
    cout<<t.x;

    return 0;
}

gives output as 1069547520

what does this value represent? how to predict this?


Solution

  • Type-puning means reinterpreting the underlying bytes of one type as bytes of another. Unions can be (mis)used for this because all members share the same memory location.

    Reading from non-active union member is undefined behaviour in C++. It is allowed in C and GNU C++.

    The correct C++ approach for trivially copyable types is to use std::memcpy:

    #include <cstring>
    
    int main()
    {
        std::uint32_t x = 12;
        
        float y;
        // This is OK, but the value of `y` is implementation-defined.
        std::memcpy(&y,&x,sizeof(x));
        // THIS IS UNDEFINED BEHAVIOUR.
        y = *reinterpret_cast<float*>(&x);
    
        static_assert(sizeof(x)==sizeof(y),"Sanity check");
    }
    

    Note that reinterpret_cast<T*>(address) is not enough because it requires T object to exist at address otherwise you are breaking the strict aliasing rule (with some exceptions). There is also no need to worry about performance degradation of using std::memcpy, with optimizations no bytes will be copied unless needed. The call will just serve as a hint to the compiler that you really meant to do that.

    Although, the example above does not exhibit undefined behaviour, the value of y still depends on precise bit representation of integers and floats which are mostly implementation-defined. In C++20 the integers are required to use 2-complement but floats are not required to adhere to e.g. IEEE 754.