如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
如何在c++中转换大端值和小端值?
为了清晰起见,我必须将二进制数据(双精度浮点值以及32位和64位整数)从一个CPU架构转换到另一个CPU架构。这并不涉及网络,因此ntoh()和类似的函数在这里不能工作。
注意:我接受的答案直接适用于我的目标编译器(这就是我选择它的原因)。然而,这里还有其他非常好的、更方便的答案。
当前回答
我真的很惊讶没有人提到htobeXX和betohXX函数。它们定义在end .h中,非常类似于网络函数htonXX。
其他回答
简单地说:
#include <climits>
template <typename T>
T swap_endian(T u)
{
static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");
union
{
T u;
unsigned char u8[sizeof(T)];
} source, dest;
source.u = u;
for (size_t k = 0; k < sizeof(T); k++)
dest.u8[k] = source.u8[sizeof(T) - k - 1];
return dest.u;
}
用法:swap_endian < uint32_t >(42)。
摘自Rob Pike的《字节顺序谬误》:
假设数据流有一个小端编码的32位整数。下面是如何提取它(假设无符号字节):
i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | ((unsigned)data[3]<<24);
如果它是big-endian,下面是如何提取它:
i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | ((unsigned)data[0]<<24);
TL;DR:不要担心你的平台原生顺序,重要的是你从中读取的流的字节顺序,你最好希望它是定义良好的。
注1:这里int和unsigned int是32位,否则类型可能需要调整。
注2:最后一个字节必须在移位前显式转换为unsigned,因为默认情况下它被提升为int,移位24位意味着操作符号位,这是未定义行为。
虽然没有使用固有函数有效,但肯定是可移植的。我的回答:
#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));
}
如果你这样做是为了网络/主机兼容性,你应该使用:
ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)
ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)
如果是出于其他原因,这里提供的byte_swap解决方案之一也可以很好地工作。
请注意,至少对于Windows, htonl()比它们的内在对应_byteswap_ulong()慢得多。前者是对ws2_32.dll的一个DLL库调用,后者是一条BSWAP汇编指令。因此,如果你正在编写一些依赖于平台的代码,为了提高速度,最好使用intrinsic:
#define htonl(x) _byteswap_ulong(x)
这对于。png图像处理尤其重要,其中所有整数都保存在大端格式中,并说明“One can use htonl()…”{用来降低典型Windows程序的速度,如果你没有准备好}。