如何在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程序的速度,如果你没有准备好}。