大小端字節序介紹見:點擊打開鏈接
大小端字節序指的是多字節類型的字節數據在內存中的存儲順序,字節內的各bit位置並不變化。
例如數據:0x12345678
在大端模式下的存儲情況爲:
地址 0 1 2 3 十六進制數據 0x12 0x34 0x56 0x78 二進制數據 0001 0010 0011 0100 0101 0110 0111 1000 在小端模式下的存儲情況爲:
地址 0 1 2 3 十六進制數據 0x78 0x56 0x34 0x12 二進制數據 0111 1000 0101 0110 0011 0100 0001 0010
由以上數據可見,大小端情況下只是字節數據的存儲位置不同,字節內的各bit位置並不變話。
那什麼情況下,大小端模式會影響bit位的存儲順序呢? 答:當結構體內的數據按位域定義時。這種情況下,結構體內按位域定義的數據類型,一定要區分大端字節序和小端字節序定義!
在對Struct(結構體)中成員進行內存分配的時候,“按排列順序分配,先分配排在前面的”:
1.大端(big endian)模式,從高位向地位分配
對字節,先分配高字節(內存低地址中),再分配低字節(內存高地址中)。
對位域,先分配高bit位,再分配低bit位。
2.小端(little endian)模式,從地位向高位分配
對字節,先分配低字節(內存低地址中),再分配高字節(內存高地址中)。
對位域,先分配低bit位,再分配高bit位。
定義如下結構體:
typedef struct tagBigOrLittleData
{
UINT32 uiA:5; /*對應數據賦值:00101*/
UINT32 uiB:9; /*對應數據賦值:000001001*/
UINT32 uiC:12;/*對應數據賦值:000000001100*/
UINT32 uiD:6; /*對應數據賦值:000110*/
}BigOrLittleData_S;
定義結構體成員:stData 各個字段賦值如上面註釋
大端模式下,stData 數據在內存中的值爲:/*00101 000 001001 00 00000011 00 000110*/
地址 | 0 | 1 | 2 | 3 |
十六進制數據 | 0x28 | 0x24 | 0x03 | 0x6 |
二進制數據 | 00101 000 |
001001 00 | 00000011 |
00 000110 |
解釋 | uiA(5)+uiB(H3) | uiB(L6)+uiC(H2) | uiC(M8) | uiC(L2)+uiD(6) |
結構體成員內存分配原則和上面描述一致:“按排列順序分配,先分配排在前面的成員,在大端模式下,對位域,先對高bit位進行分配,在對低bit位進行分配”。
小端模式下,stData 數據在內存中的值爲:/*001 00101 00 000001 00000011 000110 00*/
地址 | 0 | 1 | 2 | 3 |
十六進制數據 | 0x25 | 0x01 | 0x03 | 0x18 |
二進制數據 | 001 00101 |
00 000001 |
00000011 |
000110 00 |
解釋 | uiB(L3)+uiA(5) | uiC(L2)+uiB(H6) | uiC(M8) | uiD(6) + uiC(H2) |
結構體成員內存分配原則和上面描述一致:“按排列順序分配,先分配排在前面的成員,在小端模式下,對位域,先對低bit位進行分配,在對高bit位進行分配”。
VS2010 驗證代碼及結果(小端模式):
typedef struct tagBigOrLittleData
{
UINT32 uiA:5; /*對應數據賦值:00101*/
UINT32 uiB:9; /*對應數據賦值:000001001*/
UINT32 uiC:12;/*對應數據賦值:000000001100*/
UINT32 uiD:6; /*對應數據賦值:000110*/
}BigOrLittleData_S;
int _tmain(int argc, _TCHAR* argv[])
{
BigOrLittleData_S stData = {0};
stData.uiA = 5;
stData.uiB = 9;
stData.uiC = 12;
stData.uiD = 6;
/*001 00101 00 000001 00000011 000110 00*/
getchar();
return 0;
}
由此可見,同樣一個按位域定義的結構體,大小端模式下,數據在內存中的存儲順序是完全不一樣的,說白了,就是字節的值和位置都不一樣。
所以,如果大端定義了上面的結構體,那麼小端對應的結構體應該定義爲:
typedef struct tagBigOrLittleData
{
UINT32 uiD:6; /*對應數據賦值:000110*/
UINT32 uiC:12;/*對應數據賦值:000000001100*/
UINT32 uiB:9; /*對應數據賦值:000001001*/
UINT32 uiA:5; /*對應數據賦值:00101*/
}BigOrLittleData_S;
此時,在小端模式下,stData 數據在內存中的值爲:/*00 000110 00000011 001001 00 00101 000*/
地址 | 0 | 1 | 2 | 3 |
十六進制數據 | 0x06 | 0x03 | 0x24 | 0x28 |
二進制數據 | 00 000110 | 00000011 | 001001 00 | 00101 000 |
解釋 | uiC(L2)+uiD(6) | uiC(M8) | uiB(L6)+uiC(H2) | uiA(5)+uiB(H3) |
會發現,結構體各個位域字段“反序”定義以後,小端模式下,字節的值和大端模式的值相同了,但字節序還是反序的(0x06032428 對應 0x28240306),所以在使用時還要進行大小端字節序的轉換!
從而,結構體中位域定義的成員,爲了兼容大小端,存在以下規則:
1.結構體位域成員的定義,對每個成員的定義要區分大小端,對成員中位域的定義順序進行翻轉。
例如:
typedef struct tagBigOrLittleData
{
#ifdef BIG_ENDIAN
UINT32 uiA:5; /*對應數據賦值:00101*/
UINT32 uiB:9; /*對應數據賦值:000001001*/
UINT32 uiC:12;/*對應數據賦值:000000001100*/
UINT32 uiD:6; /*對應數據賦值:000110*/
USHORT usA:6;
USHORT usB:10
#else
UINT32 uiD:6; /*對應數據賦值:000110*/
UINT32 uiC:12;/*對應數據賦值:000000001100*/
UINT32 uiB:9; /*對應數據賦值:000001001*/
UINT32 uiA:5; /*對應數據賦值:00101*/
USHORT usB:10
USHORT usA:6;
#endif
}BigOrLittleData_S;