Question

I would like to know if the following code is an acceptable method to handle type punning in a way that doesn't break strict aliasing rules. I realize that this method relies on a GCC compiler extension, so there is no need to point that out.

template <class output_type, class input_type>
inline output_type punning_cast(const input_type& input)
{
    static_assert(std::is_pod<output_type>::value, "output_type for punning_cast must be POD");
    static_assert(std::is_pod<input_type>::value, "input_type for punning_cast must be POD");
    static_assert(sizeof(output_type) == sizeof(input_type), "input_type and output_type must be the same size");

    typedef output_type __attribute__((may_alias)) output_type_may_alias;

    return *reinterpret_cast<const output_type_may_alias*>(&input);
}

template <class output_type, class input_type>
inline output_type punning_cast(const input_type* input)
{
    static_assert(std::is_pod<output_type>::value, "output_type for punning_cast must be POD");
    static_assert(std::is_pod<input_type>::value, "input_type for punning_cast must be POD");

    typedef output_type __attribute__((may_alias)) output_type_may_alias;

    return *reinterpret_cast<const output_type_may_alias*>(input);
}

Example usage:

uint32_t float_as_int = punning_cast<uint32_t>(3.14f);

unsigned char data[4] = { 0xEF, 0xBE, 0xAD, 0xDE };
uint32_t magic = punning_cast<uint32_t>(data);
Was it helpful?

Solution

I tend to use a union for this. Something like:

template <class output_type, class input_type>
inline output_type punning_cast(const input_type& input)
{
    union {
        input_type in;
        output_type out;
    } u;

    u.in = input;
    return u.out;
}

Strictly speaking, this is Undefined Behavior in C++ (although not in C). But then so is yours, and I have yet to see a C++ compiler that does not "do what I want" for this construct... So I believe this is a fairly portable way to do type punning.

The best alternative, I think, is just to use memcpy, and that is probably what I would do for the "pointer" version of your code. A good compiler will inline the call, so there should be no performance penalty.

I find the union formulation easier to read.

[Update]

The GCC documentation says:

The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type.

So GCC, at least, specifically supports using a union.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top