工作中會遇到數據大小端問題,也就是大於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