字节序(Byte Order)

字节序(Byte Order)

字节序(Byte Order)说的是多字节数据类型(比如整数、浮点数)在内存里存储时,字节到底按什么顺序排。常见的有大端序(Big Endian)和小端序(Little Endian)两种。

  1. 大端序(Big Endian):在内存里,数据的高字节放在低地址,低字节放在高地址。
  2. 小端序(Little Endian):在内存里,数据的低字节放在低地址,高字节放在高地址。

举个例子,一个四字节的整数 0x12345678:

  • 在大端序里,它会被存成:12 34 56 78
  • 在小端序里,它会被存成:78 56 34 12

不同的计算机架构和处理器用的字节序可能不一样。比如 Intel、AMD 的 x86 架构通常是小端序,而 PowerPC、SPARC 这些架构通常是大端序。

#include <iostream>


void test()
{
    // 从左向右依次为高位字节->低位字节
    unsigned int value = 0xaabbccdd;

    unsigned char* p = (unsigned char*)&value;

    // 从低地址到高地址以此访问每个字节
    printf("address: %lld value: %x\n", (long long)(p + 0), *(p + 0));
    printf("address: %lld value: %x\n", (long long)(p + 1), *(p + 1));
    printf("address: %lld value: %x\n", (long long)(p + 2), *(p + 2));
    printf("address: %lld value: %x\n", (long long)(p + 3), *(p + 3));
}

int main()
{
    test();
    return 0;
}

程序输出结果:

address: 194812049492 value: dd
address: 194812049493 value: cc
address: 194812049494 value: bb
address: 194812049495 value: aa

从输出能看到,低地址存的是 value 的低字节,高地址存的是高字节,这就是小端模式。以后再操作字节时,我们就清楚了:访问原数据是从低字节开始的。

在网络编程里,字节序不一致会让数据传过去对端解析出错。为了解决这个问题,网络上传输数据统一用大端序,这个大端序也叫网络字节序(Network Byte Order)。Windows 和 Linux 的网络编程都提供了对应的 API,把多字节数据转成网络字节序。

下面这段示例代码在 Visual Studio 2022 里运行,需要右键项目属性,按链接器、输入、附加依赖项,加上 Ws2_32.lib:

#include <iostream>
#include <WinSock2.h>


template<class T>
void print_byte_order(T value)
{

    unsigned char* p = (unsigned char*)&value;
    for (int i = 0; i < sizeof(T); ++i)
    {
        // 从低地址到高地址以此访问每个字节
        printf("address: %lld value: %x\n", (long long)(p + i), *(p + i));
    }
    printf("\n");
}


void test()
{
    // 转换16位整数为网络字节序
    unsigned short host_short_value = 0x1234;
    unsigned short net_short_value = htons(host_short_value);
    print_byte_order(net_short_value);

    // 转换32位整数为网络字节序
    unsigned long host_long_value = 0x12345678;
    unsigned long net_long_value = htonl(host_long_value);
    print_byte_order(net_long_value);
}


int main()
{
    test();
    return 0;
}
address: 886901503232 value: 12
address: 886901503233 value: 34

address: 886901503232 value: 12
address: 886901503233 value: 34
address: 886901503234 value: 56
address: 886901503235 value: 78

从输出可以看到,用 htons、htonl 就把小端模式转成了大端模式,也就是网络字节序。