以下代码会导致编译器警告:
取消引用类型双关指针将违反严格别名规则
#include <endian.h>
template <typename T>
inline T HostToLittleEndian(T val) {
switch (sizeof(val)) {
case 1:
return val;
case 2: {
uint16_t r = htole16(*reinterpret_cast<uint16_t*>(&val));
return *reinterpret_cast<T*>(&r);
}
case 4: {
uint32_t r = htole32(*reinterpret_cast<uint32_t*>(&val));
return *reinterpret_cast<T*>(&r);
}
case 8: {
uint64_t r = htole64(*reinterpret_cast<uint64_t*>(&val));
return *reinterpret_cast<T*>(&r);
}
default:
static_assert(sizeof(val) <= 8, "Value is 64-bits or less.");
}
}
我能够使用
union
进行重构,这解决了编译器警告,但现在有 val
的额外副本。这个其他 StackOverflow 问题让我相信副本是不可避免的,这是真的吗?还是有我没有意识到的更优化的解决方案?
template <typename T>
inline T HostToLittleEndian(T val) {
union {
T value;
uint64_t u64;
uint32_t u32;
uint16_t u16;
uint8_t u8;
} data;
data.value = val;
switch (sizeof(val)) {
case 1:
break;
case 2:
data.u16 = htole16(data.u16);
break;
case 4:
data.u32 = htole32(data.u32);
break;
case 8:
data.u64 = htole64(data.u64);
break;
default:
static_assert(sizeof(val) <= 8, "Value is 64-bits or less.");
}
return data.value;
}
注意,整型和浮点类型都是有效的 T 类型。
提供
T
是一个整型,你实际上不需要强制转换,因为隐式转换应该可以正常工作,例如:
#include <type_traits>
#include <endian.h>
template <typename T>
inline T HostToLittleEndian(T val) {
static_assert(std::is_integral<T>::value, "Value must be integral");
switch (sizeof(val)) {
case 1:
return val;
case 2: {
return htole16(val);
}
case 4: {
return htole32(val);
}
case 8: {
return htole64(val);
}
default:
static_assert(sizeof(val) <= 8, "Value must be 64-bits or less.");
}
}