一、概念
小端即主机序,即内存的低地址段先存数据的低位,然后在存高位,有种由小到大存储的感觉,所以称为小端。
大端即网络序,即内存的低地址段先存数据的高位,然后在存低位,有种由小到大存储的感觉,所以称为大端。
我们最常见的X86 CPU采用的是小端,所以小端又称主机序。其实还有一些其他CPU也是大端的,但本人接触较少,不做说明了。
网络传输协议中都采用大端,so大端又称网络序。
二、小端环境中打印存储地址的示例
#include<stdio.h> #define BYTE unsigned char #define WORD32 unsigned int int main(void) { BYTE* pb = 0; WORD32 i = 0x12345678; WORD32 j; pb = (BYTE*)&i; for(j = 0; j < (sizeof(WORD32)/sizeof(BYTE)); j++) { printf("(pb+%u) value = %X \t", j,*(pb+j)); printf("address = %X \n", (pb+j)); } return 0; }
在X86+linux环境下测试,输出结果为:
(pb+0) value = 78 address = BFFFF410
(pb+1) value = 56 address = BFFFF411
(pb+2) value = 34 address = BFFFF412
(pb+3) value = 12 address = BFFFF413
三、大小端数据互转的示例
#include<stdio.h> #define BYTE unsigned char #define WORD16 unsigned short #define WORD32 unsigned int #define s_endian_swap(x) \ ( ((((x)&0x00ff)<<8)&0xff00) | \ ((((x)&0xff00)>>8)&0x00ff) ) #define l_endian_swap(x) \ ( ((((x)&0x000000ff)<<24)&0xff000000) | \ ((((x)&0x0000ff00)<<8) &0x00ff0000) | \ ((((x)&0x00ff0000)>>8) &0x0000ff00) | \ ((((x)&0xff000000)>>24)&0x000000ff) ) #ifndef ntohs #define ntohs(x) s_endian_swap(x) #endif #ifndef ntohl #define ntohl(x) l_endian_swap(x) #endif int main(void) { BYTE abData[4]; BYTE* pb = 0; WORD32 j; WORD16 wOutput; WORD32 dwOutput; /* 模拟一下网络序(大端)中数据0x12345678的存储状态 */ abData[0] = 0x12; abData[1] = 0x34; abData[2] = 0x56; abData[3] = 0x78; pb = abData; /* 不放心可以打印确认一下 */ for(j = 0; j < (sizeof(WORD32)/sizeof(BYTE)); j++) { printf("(pb+%u) value = %X \t", j,*(pb+j)); printf("address = %X \n", (pb+j)); } /* 这时候直接通过强转取值就会出错 */ wOutput = *(WORD16*)pb; dwOutput = *(WORD32*)pb; /* 看看都错了吧。可以想想为什么是这两个错误值? */ printf("the wrong wOutput = 0x%x \n", wOutput); /* 输出为0x3412 */ printf("the wrong dwOutput = 0x%x \n", dwOutput); /* 输出为0x78563412 */ /* 字节序转换宏来拯救世界了 */ wOutput = ntohs(wOutput); dwOutput = ntohl(dwOutput); /* 这下都对了吧 */ printf("the right wOutput = 0x%x \n", wOutput); /* 输出为0x1234 */ printf("the right dwOutput = 0x%x \n", dwOutput); /* 输出为0x12345678 */ return 0; }