如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
当前回答
虽然没有使用固有函数有效,但肯定是可移植的。我的回答:
#include <cstdint>
#include <type_traits>
/**
* Perform an endian swap of bytes against a templatized unsigned word.
*
* @tparam value_type The data type to perform the endian swap against.
* @param value The data value to swap.
*
* @return value_type The resulting swapped word.
*/
template <typename value_type>
constexpr inline auto endian_swap(value_type value) -> value_type
{
using half_type = typename std::conditional<
sizeof(value_type) == 8u,
uint32_t,
typename std::conditional<sizeof(value_type) == 4u, uint16_t, uint8_t>::
type>::type;
size_t const half_bits = sizeof(value_type) * 8u / 2u;
half_type const upper_half = static_cast<half_type>(value >> half_bits);
half_type const lower_half = static_cast<half_type>(value);
if (sizeof(value_type) == 2u)
{
return (static_cast<value_type>(lower_half) << half_bits) | upper_half;
}
return ((static_cast<value_type>(endian_swap(lower_half)) << half_bits) |
endian_swap(upper_half));
}
其他回答
如果您这样做是为了在不同平台之间传输数据,请查看ntoh和hton函数。
和在C中一样:
short big = 0xdead;
short little = (((big & 0xff)<<8) | ((big & 0xff00)>>8));
您还可以声明一个无符号字符的向量,将输入值memcpy放入其中,将字节反向转换为另一个向量,然后将字节memcpy取出,但这将花费比旋转位长几个数量级的时间,特别是对于64位值。
从大端序到小端序的过程与从小端序到大端序的过程是一样的。
下面是一些示例代码:
void swapByteOrder(unsigned short& us)
{
us = (us >> 8) |
(us << 8);
}
void swapByteOrder(unsigned int& ui)
{
ui = (ui >> 24) |
((ui<<8) & 0x00FF0000) |
((ui>>8) & 0x0000FF00) |
(ui << 24);
}
void swapByteOrder(unsigned long long& ull)
{
ull = (ull >> 56) |
((ull<<40) & 0x00FF000000000000) |
((ull<<24) & 0x0000FF0000000000) |
((ull<<8) & 0x000000FF00000000) |
((ull>>8) & 0x00000000FF000000) |
((ull>>24) & 0x0000000000FF0000) |
((ull>>40) & 0x000000000000FF00) |
(ull << 56);
}
这是我想到的一个通用版本,用于在适当的位置交换值。如果性能存在问题,其他建议会更好。
template<typename T>
void ByteSwap(T * p)
{
for (int i = 0; i < sizeof(T)/2; ++i)
std::swap(((char *)p)[i], ((char *)p)[sizeof(T)-1-i]);
}
免责声明:我还没有尝试编译或测试它。
如果你正在使用Visual c++,请执行以下操作:包含intrin.h并调用以下函数:
对于16位数字:
unsigned short _byteswap_ushort(unsigned short value);
对于32位数字:
unsigned long _byteswap_ulong(unsigned long value);
对于64位数字:
unsigned __int64 _byteswap_uint64(unsigned __int64 value);
8位数字(字符)不需要转换。
此外,这些仅定义为无符号值,它们也适用于有符号整数。
对于浮点数和双精度数,要比普通整数困难得多,因为它们可能在主机的字节顺序中。你可以在大端机器上得到小端浮点数,反之亦然。
其他编译器也有类似的特性。
例如,在GCC中,你可以直接调用一些内置程序,如下所示:
uint32_t __builtin_bswap32 (uint32_t x)
uint64_t __builtin_bswap64 (uint64_t x)
(不需要包含任何东西)。Afaik bits.h也以非gcc为中心的方式声明了相同的函数。
16位交换就是位旋转。
顺便说一句,调用这些内在函数而不是调用自己的内在函数可以获得最好的性能和代码密度。