我想知道以下代码是否是一种可接受的方法,以不破坏严格别名规则的方式处理类型惩罚。我意识到这个方法依赖于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);
答案 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
公式更容易阅读。
[更新]
从不同的工会成员那里读书的做法 最近写的(称为“打字”)很常见。即使
-fstrict-aliasing
,如果通过联合类型访问内存,则允许类型惩罚。
因此,GCC至少特别支持使用联盟。