使用模板键入punning cast

Chr*_*s_F 4 c++ gcc casting type-punning c++11

我想知道以下代码是否是一种可接受的方法,以不破坏严格别名规则的方式处理类型惩罚.我意识到这个方法依赖于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);
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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);
Run Code Online (Sandbox Code Playgroud)

Nem*_*emo 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;
}
Run Code Online (Sandbox Code Playgroud)

严格来说,这是C++中的未定义行为(尽管不是在C中).但是你的情况也是如此,我还没有看到一个C++编译器没有为我的构造"做我想做的事情"...所以我相信这是一种相当便携的方式来进行类型惩罚.

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

我发现union配方更容易阅读.

[更新]

海湾合作委员会的文件说:

从不同的工会成员阅读的做法比最近写的那个(称为"打字式")很常见.即使使用 -fstrict-aliasing,只要通过union类型访问内存,就允许类型惩罚.

所以GCC至少特别支持使用联盟.