大端&小端&网络序&主机序&比特序&位域

    xiaoxiao2025-02-17  20

    一、大端&小端&网络序&主机序&比特序&位域     转自:https://blog.csdn.net/u014279330/article/details/78326723

    Little endian:  将低序字节存储在起始地址  Big endian:     将高序字节存储在起始地址 

    例子:在内存中双字0x01020304(DWORD)的存储方式  内存地址(注:内存地址从左到右为由低到高)      4000 4001 4002 4003  LE  04   03   02   01     --- 符合人的思维,低值存放于低地址,高值存放于高地址 BE  01   02   03   04     --- 直观,数值阅读顺序与地址顺序一致,或者说在内存中填充的顺序与阅读的一致

    可以通过以下小程序直接显示当前运行机器的字节序:

    short int x; char x0; x=0x1122; x0=((char*)&x)[0]; 若x0=0x11,则是大端; 若x0=0x22,则是小端......

    网络字节序为大端序,其实大端序或者网络序,我们可以当做一串字符串一样处理。例如 192.168.106.3

    以下程序在x86平台执行结果为:

    printf(“0x%x”, inet_addr("192.168.106.3"));

    printf(“0x%x”, ntohl(inet_addr("192.168.106.3")));

    printf(“0x%x”, htonl(inet_addr("192.168.106.3")));

    0x36aa8c0

    0xc0a86a3

    0xc0a86a3

    其实"192.168.106.3"就是一个字符串,在x86平台(小端序),是将字符串的低地址(左边为低)保存在低位,所以将192,即c0存放在低位,即在内存中保存的顺序为

    内存:       低----->高

    保存的值:    c0  a8  6a  3

    转为int型,即为为0x36aa8c0;

    而ntohl会将整个顺序调换(小端序主机上),结果为0xc0a86a3;同时我们看到htonl实现其实和ntohl一样。

    ntohs等函数为主机序与网络序转换的函数: 在使用little endian的系统中 这些函数会把字节序进行转换  在使用big endian类型的系统中 这些函数会定义成空宏 

    不同的CPU上运行不同的操作系统,字节序也是不同的,参见下表。  处理器 操作系统 字节排序  Alpha 全部 Little endian  HP-PA NT Little endian  HP-PA UNIX Big endian  Intelx86 全部 Little endian <-----x86系统是小端字节序系统  Motorola680x() 全部 Big endian  MIPS NT Little endian  MIPS UNIX Big endian  PowerPC NT Little endian  PowerPC 非NT Big endian <-----PPC系统是大端字节序系统  RS/6000 UNIX Big endian  SPARC UNIX Big endian  IXP1200 ARM核心 全部 Little endian

    在定义协议报文,涉及到位域时,也需要区分大小端,如ip头version为高位,ihl为低位,则在小端情况下(低值在地址低位),version定义在后,而大端正好相反。

    struct iphdr    {  #if __BYTE_ORDER == __LITTLE_ENDIAN      unsigned int ihl:4;      unsigned int version:4;  #elif __BYTE_ORDER == __BIG_ENDIAN      unsigned int version:4;      unsigned int ihl:4;  #else  # error "Please fix <bits/endian.h>"  #endif      u_int8_t tos;      u_int16_t tot_len;      u_int16_t id;      u_int16_t frag_off;      u_int8_t ttl;      u_int8_t protocol;      u_int16_t check;      u_int32_t saddr;      u_int32_t daddr;      /*The options start here. */    };

    二、字节序之大小端与MSB和LSB    转自:

    6、LSB与MSB举例

    开始举栗子:

        假设一个一字节的数0x9A转换成2进制为“1001 1010”,那么LSB与MSB则应该是这样分布的:

    7、大小端举例

    开始举栗子:

        假设有一个32位4字节的数,用16进制表示为:0x12345678;这个数将要从内存地址为0x40000开始存放;当计算机字节序为

    大端时(它应该是这么存放的):

    小端时(它应该是这么存放的):

       顺便将一下最【高有效字节】和【最低有效字节】,其实原理跟MSB和LSB相同,以上面大端存放内容为例,看下面这个图应该就明白了:

    8、如何辨别不同平台的大小端

    #include <stdio.h> int main() {     typedef union{         int a;         char b;     }UN_TEST;    /* 定义一个联合体数据类型 */       UN_TEST d;     d.a = 1;     if(d.b == 1)     {         printf("Little Endian\n");     }     else     {         printf("Big Endian\n");     }       return 0; }       

    最新回复(0)