工作中会遇到数据大小端问题,也就是大于1个字节的数据在内存中是怎么存放的(内存是按字节来存放数据的,每个内存地址只放1个字节)。
大小端解释:
大端:低地址放高位数据,高地址放低位数据
小端:低地址放低位数据,高地址放高位数据
总结一句话:按内存地址增长的顺序,先放高位就据就是大端,先放低位数据就是小端。
比如32bit的CPU:
读数据:(假设内存0x00000000,0x00000001,0x00000002,0x00000003四个地址分别存放:0xaa,0xbb,0xcc,0xdd四个字节)
大端读出来的结果是:0xaabbccdd
小端读出来的结果是:0xddccbbaa
存数据:(假设要把0xaabbccdd存放到0x00000000地址)
大端写入的结果是:0x00000000(0xaa) 0x00000001(0xbb) 0x00000002(0xcc) 0x00000003(0xdd)
小端写入的结果是:0x00000000(0xdd) 0x00000001(0xcc) 0x00000002(0xbb) 0x00000003(0xaa)
PS:X86是小端的,KEIL C51是大端的,ARM DSP是小端的,有些ARM大小端可配置的。
几种判断大小端的程序:
linux操作系统对大小端的判断
static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
(如果ENDIANNESS=’l’表示系统为little endian,为’b’表示big endian )。
C语言判断
/* 1 : little-endian *//* 0 : big-endian */
int islittle_endian()
{
union w { int a; char b; } c;
c.a = 1;
return (c.b);
}
由于网络字节序是大端的,此时对于大端的处理器,字节序是不需要改变的。而对于小端的处理器则需要转变。
#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
#define htons(A) (A)
#define htonl(A) (A)
#define ntohs(A) (A)
#define ntohl(A) (A)
#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
#define htons(A) ((((uint16_t)(A) & 0xff00) >> 8 ) | \\
(((uint16_t)(A) & 0x00ff) << 8 ))
#define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \\
(((uint32_t)(A) & 0x00ff0000) >> 8 ) | \\
(((uint32_t)(A) & 0x0000ff00) << 8 ) | \\
(((uint32_t)(A) & 0x000000ff) << 24))
#define ntohs htons
#define ntohl htohl
#else
#error Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both.
#endif