关于linux:C ++中的64位ntohl()?

64 bit ntohl() in C++?

htonl()的手册页似乎建议您只能将其用于最多32位值。 (实际上,ntohl()是为无符号长整数定义的,在我的平台上为32位。我想如果无符号长整数为8字节,则适用于64位整数)。

我的问题是我需要将64位整数(在我的情况下,这是一个无符号的long long)从big endian转换为little endian。现在,我需要进行特定的转换。但是如果目标平台为大端字节序,该函数(如ntohl())不会转换我的64位值,那就更好了。 (我宁愿避免添加自己的预处理器魔术来执行此操作)。

我可以使用什么?我想要一些标准的东西(如果存在的话),但我愿意接受实施建议。我已经看到过去使用联合完成这种类型的转换。我想我可以有一个unsigned long long和一个char [8]的联合。然后相应地交换字节。 (显然会在大端字节序的平台上中断)。


文档:Linux(glibc> = 2.9)或FreeBSD上的man htobe64

不幸的是,在2009年,OpenBSD,FreeBSD和glibc(Linux)并没有很好地协同工作来为此创建一个(非内核API)libc标准。

当前,这段简短的预处理器代码:

1
2
3
4
5
6
7
8
9
10
#if defined(__linux__)
#  include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#  include <sys/endian.h>
#elif defined(__OpenBSD__)
#  include <sys/types.h>
#  define be16toh(x) betoh16(x)
#  define be32toh(x) betoh32(x)
#  define be64toh(x) betoh64(x)
#endif

(在Linux和OpenBSD上测试)应该隐藏差异。它为您提供了这4个平台上的Linux / FreeBSD风格的宏。

使用示例:

1
2
3
4
5
6
7
  #include <stdint.h>    // For 'uint64_t'

  uint64_t  host_int = 123;
  uint64_t  big_endian;

  big_endian = htobe64( host_int );
  host_int = be64toh( big_endian );

这是目前最"标准的C库"式方法。


我建议阅读以下内容:http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

uint64_t
ntoh64(const uint64_t *input)
{
    uint64_t rval;
    uint8_t *data = (uint8_t *)&rval;

    data[0] = *input >> 56;
    data[1] = *input >> 48;
    data[2] = *input >> 40;
    data[3] = *input >> 32;
    data[4] = *input >> 24;
    data[5] = *input >> 16;
    data[6] = *input >> 8;
    data[7] = *input >> 0;

    return rval;
}

uint64_t
hton64(const uint64_t *input)
{
    return (ntoh64(input));
}

int
main(void)
{
    uint64_t ull;

    ull = 1;
    printf("%"PRIu64"
"
, ull);

    ull = ntoh64(&ull);
    printf("%"PRIu64"
"
, ull);

    ull = hton64(&ull);
    printf("%"PRIu64"
"
, ull);

    return 0;
}

将显示以下输出:

1
2
3
1
72057594037927936
1

如果删除高4个字节,则可以使用ntohl()进行测试。

您也可以将其转换为C ++中很好的模板化函数,该函数可以在任何大小的整数上工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T>
static inline T
hton_any(const T &input)
{
    T output(0);
    const std::size_t size = sizeof(input);
    uint8_t *data = reinterpret_cast<uint8_t *>(&output);

    for (std::size_t i = 0; i < size; i++) {
        data[i] = input >> ((size - i - 1) * 8);
    }

    return output;
}

现在您的128位安全了!


要检测您的字节序,请使用以下联合:

1
2
3
4
5
union {
    unsigned long long ull;
    char c[8];
} x;
x.ull = 0x0123456789abcdef; // may need special suffix for ULL.

然后,您可以检查x.c[]的内容以检测每个字节到达的位置。

为了进行转换,我将使用该检测代码一次来查看平台使用的字节序,然后编写我自己的函数进行交换。

您可以使它动态化,以便代码可以在任何平台上运行(检测一次,然后在转换代码内使用开关来选择正确的转换),但是,如果您只打算使用一个平台,则只需在单独的程序中进行一次检测,然后编写一个简单的转换例程,以确保您记录它仅在该平台上运行(或已经过测试)。

这是我摘录的一些示例代码。尽管没有进行全面的测试,但是应该足以使您入门。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2

static unsigned long long cvt(unsigned long long src) {
    static int typ = TYP_INIT;
    unsigned char c;
    union {
        unsigned long long ull;
        unsigned char c[8];
    } x;

    if (typ == TYP_INIT) {
        x.ull = 0x01;
        typ = (x.c[7] == 0x01) ? TYP_BIGE : TYP_SMLE;
    }

    if (typ == TYP_SMLE)
        return src;

    x.ull = src;
    c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
    c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
    c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
    c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
    return x.ull;
}

int main (void) {
    unsigned long long ull = 1;
    ull = cvt (ull);
    printf ("%llu
"
,ull);
    return 0;
}

请记住,这只是检查纯的大/小字节序。如果您有一些奇怪的变体,例如以{5,2,3,1,0,7,6,4}的顺序存储字节,则cvt()会有点复杂。这样的体系结构不应该存在,但我不轻视我们在微处理器行业的朋友的疯狂:-)

还请记住,这在技术上是不确定的行为,因为除了最后一个写入的字段外,您不应通过任何其他字段访问工会成员。它可能适用于大多数实现,但从纯粹的角度来看,您可能应该硬着头皮,使用宏定义自己的例程,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Assumes 64-bit unsigned long long.
unsigned long long switchOrderFn (unsigned long long in) {
    in  = (in && 0xff00000000000000ULL) >> 56
        | (in && 0x00ff000000000000ULL) >> 40
        | (in && 0x0000ff0000000000ULL) >> 24
        | (in && 0x000000ff00000000ULL) >> 8
        | (in && 0x00000000ff000000ULL) << 8
        | (in && 0x0000000000ff0000ULL) << 24
        | (in && 0x000000000000ff00ULL) << 40
        | (in && 0x00000000000000ffULL) << 56;
    return in;
}
#ifdef ULONG_IS_NET_ORDER
    #define switchOrder(n) (n)
#else
    #define switchOrder(n) switchOrderFn(n)
#endif


有些BSD系统具有betoh64来满足您的需求。


快速回答

1
2
3
4
5
6
7
8
#include <endian.h>    // __BYTE_ORDER __LITTLE_ENDIAN
#include <byteswap.h>  // bswap_64()

uint64_t value = 0x1122334455667788;

#if __BYTE_ORDER == __LITTLE_ENDIAN
value = bswap_64(value);  // Compiler builtin GCC/Clang
#endif

头文件

正如zhaorufei所报告的(请参阅她/他的评论),endian.h不是C ++标准头文件,并且宏__BYTE_ORDER__LITTLE_ENDIAN可能未定义。因此,#if语句是不可预测的,因为未定义的宏被视为0

如果您想分享C ++优雅的技巧来检测字节序,请编辑此答案。

可移植性

此外,宏bswap_64()可用于GCC和Clang编译器,但不适用于Visual C ++编译器。要提供可移植的源代码,可能会受到以下代码段的启发:

1
2
3
4
5
6
7
8
#ifdef _MSC_VER
  #include <stdlib.h>
  #define bswap_16(x) _byteswap_ushort(x)
  #define bswap_32(x) _byteswap_ulong(x)
  #define bswap_64(x) _byteswap_uint64(x)
#else
  #include <byteswap.h>  // bswap_16 bswap_32 bswap_64
#endif

另请参阅更可移植的源代码:跨平台_byteswap_uint64

C ++ 14 constexpr模板函数

通用hton(),用于16位,32位,64位等

1
2
3
4
5
6
7
8
9
10
11
12
#include <endian.h>   // __BYTE_ORDER __LITTLE_ENDIAN
#include   // std::reverse()

template <typename T>
constexpr T htonT (T value) noexcept
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
  char* ptr = reinterpret_cast<char*>(&value);
  std::reverse(ptr, ptr + sizeof(T));
#endif
  return value;
}

C ++ 11 constexpr模板函数

  • C ++ 11不允许在constexpr函数中使用局部变量。
    因此,诀窍是使用具有默认值的参数。
  • 此外,C ++ 11 constexpr函数必须包含一个单个表达式。
    因此,主体由一个返回值组成,该返回值带有一些逗号分隔的语句。
1
2
3
4
5
6
7
8
9
10
template <typename T>
constexpr T htonT (T value, char* ptr=0) noexcept
{
  return
#if __BYTE_ORDER == __LITTLE_ENDIAN
    ptr = reinterpret_cast<char*>(&value),
    std::reverse(ptr, ptr + sizeof(T)),
#endif
    value;
}

使用-Wall -Wextra -pedantic的clang-3.5和GCC-4.9都没有编译警告
(请参阅编译并在coliru上运行输出)。

C ++ 11 constexpr模板SFINAE函数

但是,以上版本不允许将constexpr变量创建为:

1
constexpr int32_t hton_six = htonT( int32_t(6) );

最后,我们需要根据16/32/64位来分离(专门化)功能。
但是我们仍然可以保留泛型函数。
(请参阅coliru上的完整代码段)

下面的C ++ 11代码段使用特征std::enable_if来利用"替代失败不是错误"(SFINAE)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
template <typename T>
constexpr typename std::enable_if<sizeof(T) == 2, T>::type
htonT (T value) noexcept
{
   return  ((value & 0x00FF) << 8)
         | ((value & 0xFF00) >> 8);
}

template <typename T>
constexpr typename std::enable_if<sizeof(T) == 4, T>::type
htonT (T value) noexcept
{
   return  ((value & 0x000000FF) << 24)
         | ((value & 0x0000FF00) <<  8)
         | ((value & 0x00FF0000) >>  8)
         | ((value & 0xFF000000) >> 24);
}

template <typename T>
constexpr typename std::enable_if<sizeof(T) == 8, T>::type
htonT (T value) noexcept
{
   return  ((value & 0xFF00000000000000ull) >> 56)
         | ((value & 0x00FF000000000000ull) >> 40)
         | ((value & 0x0000FF0000000000ull) >> 24)
         | ((value & 0x000000FF00000000ull) >>  8)
         | ((value & 0x00000000FF000000ull) <<  8)
         | ((value & 0x0000000000FF0000ull) << 24)
         | ((value & 0x000000000000FF00ull) << 40)
         | ((value & 0x00000000000000FFull) << 56);
}

或者是基于内置编译器宏和C ++ 14语法std::enable_if_t作为std::enable_if::type的快捷方式的更短版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <typename T>
constexpr typename std::enable_if_t<sizeof(T) == 2, T>
htonT (T value) noexcept
{
    return bswap_16(value);  // __bswap_constant_16
}

template <typename T>
constexpr typename std::enable_if_t<sizeof(T) == 4, T>
htonT (T value) noexcept
{
    return bswap_32(value);  // __bswap_constant_32
}

template <typename T>
constexpr typename std::enable_if_t<sizeof(T) == 8, T>
htonT (T value) noexcept
{
    return bswap_64(value);  // __bswap_constant_64
}

第一版测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
std::uint8_t uc = 'B';                  std::cout <<std::setw(16)<< uc <<'
'
;
uc = htonT( uc );                       std::cout <<std::setw(16)<< uc <<'
'
;

std::uint16_t us = 0x1122;              std::cout <<std::setw(16)<< us <<'
'
;
us = htonT( us );                       std::cout <<std::setw(16)<< us <<'
'
;

std::uint32_t ul = 0x11223344;          std::cout <<std::setw(16)<< ul <<'
'
;
ul = htonT( ul );                       std::cout <<std::setw(16)<< ul <<'
'
;

std::uint64_t uL = 0x1122334455667788; std::cout <<std::setw(16)<< uL <<'
'
;
uL = htonT( uL );                      std::cout <<std::setw(16)<< uL <<'
'
;

第二版测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
constexpr uint8_t  a1 = 'B';               std::cout<<std::setw(16)<<a1<<'
'
;
constexpr auto     b1 = htonT(a1);         std::cout<<std::setw(16)<<b1<<'
'
;

constexpr uint16_t a2 = 0x1122;            std::cout<<std::setw(16)<<a2<<'
'
;
constexpr auto     b2 = htonT(a2);         std::cout<<std::setw(16)<<b2<<'
'
;

constexpr uint32_t a4 = 0x11223344;        std::cout<<std::setw(16)<<a4<<'
'
;
constexpr auto     b4 = htonT(a4);         std::cout<<std::setw(16)<<b4<<'
'
;

constexpr uint64_t a8 = 0x1122334455667788;std::cout<<std::setw(16)<<a8<<'
'
;
constexpr auto     b8 = htonT(a8);         std::cout<<std::setw(16)<<b8<<'
'
;

输出量

1
2
3
4
5
6
7
8
               B
               B
            1122
            2211
        11223344
        44332211
1122334455667788
8877665544332211

代码生成

在线C ++编译器gcc.godbolt.org指示生成的代码。

g++-4.9.2 -std=c++14 -O3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::enable_if<(sizeof (unsigned char))==(1), unsigned char>::type htonT<unsigned char>(unsigned char):
    movl    %edi, %eax
    ret
std::enable_if<(sizeof (unsigned short))==(2), unsigned short>::type htonT<unsigned short>(unsigned short):
    movl    %edi, %eax
    rolw    $8, %ax
    ret
std::enable_if<(sizeof (unsigned int))==(4), unsigned int>::type htonT<unsigned int>(unsigned int):
    movl    %edi, %eax
    bswap   %eax
    ret
std::enable_if<(sizeof (unsigned long))==(8), unsigned long>::type htonT<unsigned long>(unsigned long):
    movq    %rdi, %rax
    bswap   %rax
    ret

clang++-3.5.1 -std=c++14 -O3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
std::enable_if<(sizeof (unsigned char))==(1), unsigned char>::type htonT<unsigned char>(unsigned char): # @std::enable_if<(sizeof (unsigned char))==(1), unsigned char>::type htonT<unsigned char>(unsigned char)
    movl    %edi, %eax
    retq

std::enable_if<(sizeof (unsigned short))==(2), unsigned short>::type htonT<unsigned short>(unsigned short): # @std::enable_if<(sizeof (unsigned short))==(2), unsigned short>::type htonT<unsigned short>(unsigned short)
    rolw    $8, %di
    movzwl  %di, %eax
    retq

std::enable_if<(sizeof (unsigned int))==(4), unsigned int>::type htonT<unsigned int>(unsigned int): # @std::enable_if<(sizeof (unsigned int))==(4), unsigned int>::type htonT<unsigned int>(unsigned int)
    bswapl  %edi
    movl    %edi, %eax
    retq

std::enable_if<(sizeof (unsigned long))==(8), unsigned long>::type htonT<unsigned long>(unsigned long): # @std::enable_if<(sizeof (unsigned long))==(8), unsigned long>::type htonT<unsigned long>(unsigned long)
    bswapq  %rdi
    movq    %rdi, %rax
    retq

注意:我的原始答案不符合C ++ 11- constexpr

此答案在Public Domain CC0 1.0 Universal中


一个行宏,可在小型字节序计算机上进行64位交换。

1
#define bswap64(y) (((uint64_t)ntohl(y)) << 32 | ntohl(y>>32))


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
uint32_t SwapShort(uint16_t a)
{
  a = ((a & 0x00FF) << 8) | ((a & 0xFF00) >> 8);
  return a;
}

uint32_t SwapWord(uint32_t a)
{
  a = ((a & 0x000000FF) << 24) |
      ((a & 0x0000FF00) <<  8) |
      ((a & 0x00FF0000) >>  8) |
      ((a & 0xFF000000) >> 24);
  return a;
}

uint64_t SwapDWord(uint64_t a)
{
  a = ((a & 0x00000000000000FFULL) << 56) |
      ((a & 0x000000000000FF00ULL) << 40) |
      ((a & 0x0000000000FF0000ULL) << 24) |
      ((a & 0x00000000FF000000ULL) <<  8) |
      ((a & 0x000000FF00000000ULL) >>  8) |
      ((a & 0x0000FF0000000000ULL) >> 24) |
      ((a & 0x00FF000000000000ULL) >> 40) |
      ((a & 0xFF00000000000000ULL) >> 56);
  return a;
}


不依赖于输入大小的通用版本怎么样(上面的某些实现假定unsigned long long是64位,不一定总是正确的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    // converts an arbitrary large integer (preferrably >=64 bits) from big endian to host machine endian
    template<typename T> static inline T bigen2host(const T& x)
    {
        static const int one = 1;
        static const char sig = *(char*)&one;

        if (sig == 0) return x; // for big endian machine just return the input

        T ret;
        int size = sizeof(T);
        char* src = (char*)&x + sizeof(T) - 1;
        char* dst = (char*)&ret;

        while (size-- > 0) *dst++ = *src--;

        return ret;
    }


怎么样:

1
2
3
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) |
    ntohl( ((uint32_t)(x >> 32)) ) )                                        
#define htonll(x) ntohll(x)

一种简单的方法是分别在两个部分上使用ntohl:

1
2
3
4
5
6
7
8
9
10
11
12
unsigned long long htonll(unsigned long long v) {
    union { unsigned long lv[2]; unsigned long long llv; } u;
    u.lv[0] = htonl(v >> 32);
    u.lv[1] = htonl(v & 0xFFFFFFFFULL);
    return u.llv;
}

unsigned long long ntohll(unsigned long long v) {
    union { unsigned long lv[2]; unsigned long long llv; } u;
    u.llv = v;
    return ((unsigned long long)ntohl(u.lv[0]) << 32) | (unsigned long long)ntohl(u.lv[1]);
}


我喜欢工会的回答,非常简洁。尽管我认为联合解决方案的分配较少,并且可能更快,但通常我只是在小端和大端之间转换而已:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//note UINT64_C_LITERAL is a macro that appends the correct prefix
//for the literal on that platform
inline void endianFlip(unsigned long long& Value)
{
   Value=
   ((Value &   UINT64_C_LITERAL(0x00000000000000FF)) << 56) |
   ((Value &   UINT64_C_LITERAL(0x000000000000FF00)) << 40) |
   ((Value &   UINT64_C_LITERAL(0x0000000000FF0000)) << 24) |
   ((Value &   UINT64_C_LITERAL(0x00000000FF000000)) << 8)  |
   ((Value &   UINT64_C_LITERAL(0x000000FF00000000)) >> 8)  |
   ((Value &   UINT64_C_LITERAL(0x0000FF0000000000)) >> 24) |
   ((Value &   UINT64_C_LITERAL(0x00FF000000000000)) >> 40) |
   ((Value &   UINT64_C_LITERAL(0xFF00000000000000)) >> 56);
}

然后,要检测是否甚至需要在不使用宏魔术的情况下进行翻转,可以执行类似Pax的操作,当将short分配给0x0001时,在相反的endian系统上它将为0x0100。

所以:

1
2
3
4
5
6
7
8
9
10
11
12
13
unsigned long long numberToSystemEndian
(
    unsigned long long In,
    unsigned short SourceEndian
)
{
   if (SourceEndian != 1)
   {
      //from an opposite endian system
      endianFlip(In);
   }
   return In;
}

因此,要使用此功能,您需要将SourceEndian用作指示符,以传达输入数字的字节序。这可以存储在文件中(如果这是序列化问题),也可以通过网络进行通信(如果这是网络序列化问题)。


htonl可以通过以下步骤完成

  • 如果其大端系统直接返回该值。无需进行任何转换。如果是小型字节序系统,则需要执行以下转换。
  • 取32位LSB并应用" htonl"并移位32次。
  • 取MSB 32位(通过将uint64_t值右移32次)并应用'htonl'
  • 现在,对在第二步和第三步中接收到的值应用按位或。

同样对于ntohll

1
2
#define HTONLL(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
#define NTOHLL(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))

您还可以删除以上2个定义的函数。


1
2
3
4
5
6
7
8
9
10
11
12
template <typename T>
static T ntoh_any(T t)
{
    static const unsigned char int_bytes[sizeof(int)] = {0xFF};
    static const int msb_0xFF = 0xFF << (sizeof(int) - 1) * CHAR_BIT;
    static bool host_is_big_endian = (*(reinterpret_cast<const int *>(int_bytes)) & msb_0xFF ) != 0;
    if (host_is_big_endian) { return t; }

    unsigned char * ptr = reinterpret_cast<unsigned char *>(&t);
    std::reverse(ptr, ptr + sizeof(t) );
    return t;
}

适用于2个字节,4个字节,8个字节和16个字节(如果您具有128位整数)。应与操作系统/平台无关。


假设您正在使用64位OS的Linux上进行编码;大多数系统具有htole(x)ntobe(x)等,这些通常是各种bswap的宏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <endian.h>
#include <byteswap.h>

unsigned long long htonll(unsigned long long val)
{
    if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
    else return __bswap_64(val);
}

unsigned long long ntohll(unsigned long long val)
{
    if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
    else return __bswap_64(val);
}

边注;这些只是调用以交换字节顺序的函数。例如,如果在大端网络中使用Little Endian,但是如果使用大端编码,则这将不必要地颠倒字节顺序,因此可能需要进行一些" if __BYTE_ORDER == __LITTLE_ENDIAN"检查,以使代码更易于移植,分派根据您的需要。

更新:编辑以显示字节序检查的示例


任何值大小的通用功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T>
T swap_endian (T value)
{
    union {
        T src;
        unsigned char dst[sizeof(T)];
    } source, dest;

    source.src = value;
    for (size_t k = 0; k < sizeof(T); ++k)
        dest.dst[k] = source.dst[sizeof(T) - k - 1];

    return dest.src;
}


通常无需知道机器的字节序即可将主机整数转换为网络顺序。不幸的是,只有当您以字节(而不是另一个整数)形式写出净订单值时,这种情况才成立:

1
2
3
4
5
static inline void short_to_network_order(uchar *output, uint16_t in)
{
    output[0] = in>>8&0xff;
    output[1] = in&0xff;
}

(根据需要扩展为更大的数字)。

这将(a)在任何体系结构上都有效,因为在任何时候我都不会使用有关整数在内存中的布局方式的专门知识,并且(b)在现代大编译器体系结构中,由于现代编译器并不笨拙,因此应该在大多数情况下对其进行优化。

缺点当然是,它与htonl()和friends的标准接口不同(我不认为这是缺点,因为htonl()的设计不是imo的选择)。