使用模板键入punning cast

时间:2014-05-10 02:47:38

标签: c++ gcc c++11 casting type-punning

我想知道以下代码是否是一种可接受的方法,以不破坏严格别名规则的方式处理类型惩罚。我意识到这个方法依赖于GCC编译器扩展,所以没有必要指出它。

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);
}

使用示例:

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);

1 个答案:

答案 0 :(得分:5)

我倾向于使用联盟。类似的东西:

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;
}

严格来说,这是Undefined Behavior in C++(尽管not in C)。但是你的情况也是如此,我还没有看到一个C ++编译器没有为我的构造“做我想做的事情”...所以我相信这是一种相当便携的方式来进行打字。

我认为,最好的选择就是使用memcpy,这可能就是我为代码的“指针”版本所做的。一个好的编译器会内联调用,所以不应该有性能损失。

我发现union公式更容易阅读。

[更新]

GCC documentation说:

  

从不同的工会成员那里读书的做法   最近写的(称为“打字”)很常见。即使   -fstrict-aliasing,如果通过联合类型访问内存,则允许类型惩罚。

因此,GCC至少特别支持使用联盟。