大端序/小端序

​ 字节序即字节的存储顺序,如果数据都是单字节的,那怎么存储无所谓了,但是对于多字节数据,比如int,double等,就要考虑存储的顺序了。字节序是硬件层面的东西,通常只和你使用的处理器架构有关,而和编程语言无关。字节序分为大端序和小端序。

  • 大端序将高序字节存储在起始地址,一个占有4个字节类型的数据0x00112233在内存中如下分布:

    大端模式

  • 小端序将低序字节存储在起始地址,数据0x00112233在内存中如下分布:

    小端模式


    比特序/位域

    ​ 位域的写入顺序和当前系统字节序有关:先定义的位域在大端环境从最高bit位(MSB)开始分配。如果为小端环境则先定义的位域从最低bit位(LSB)开始分配。(CPU操作内存还是以字节为单位的)

    struct bitfield
    {
        uint8_t a:1;
        uint8_t b:2;
        uint8_t c:3;
        uint8_t d:2;
    }bf;
    bf.a = 1;
    bf.b = 2;
    bf.c = 3;
    bf.d = 3;
    
  • 大端系统:struct bitfield bf 在内存中如下分布:

    MSB

  • 小端系统:struct bitfield bf 在内存中如下分布:

LSB

​ 比特的发送、接收顺序对CPU、软件都是不可见的,(对诸如PHY的serdes(串行器和解串器)以及网卡写总线的硬件设计是非常重要的)因为我们的网卡会给我们处理这种转换,在发送的时候按照小端序发送比特位,在接收的时候网卡会把接收到的比特序转换成主机的比特序,下面是一个小端机器发送一个int整型给一个大端机器的示意图:

bit网络发送

​ 因为不同的平台的比特序是不同的,但是我们定义的位域需要根据平台的大小端进行转换,以iphdr为例:

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8    ihl:4,
                version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
        __u8    version:4,
                ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif
        __u8    tos;
        __u16   tot_len;
        __u16   id;
        __u16   frag_off;
        __u8    ttl;
        __u8    protocol;
        __u16   check;
        __u32   saddr;
        __u32   daddr;
        /*The options start here. */
};

网络序/主机序

  • 网络序:采用大端的排序方式
  • 主机序:不同的CPU有不同的字节序类型这些字节序是指整数在内存中保存的顺序,CPU上运行不同的操作系统,字节序也是不同的
处理器 操作系统 字节排序
Alpha 全部 Little endian
HP-PA NT Little endian
HP-PA UNIX Big endian
Intelx86 全部 Little endian
Motorola680x 全部 Big endian
MIPS NT Little endian
MIPS UNIX Big endian
PowerPC NT Little endian
PowerPC 非NT Big endian
RS/6000 UNIX Big endian
SPARC UNIX Big endian
IXP1200 ARM核心 全部 Little endian

参考链接