談到字節序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存儲數據,而x86系列則采用little endian方式存儲數據。那么究竟什么是big endian,什么又是little endian呢?
其實big endian是指低地址存放最高有效字節(MSB),而little endian則是低地址存放最低有效字節(LSB)。
用文字說明可能比較抽象,下面用圖像加以說明。比如數字0x12345678在兩種不同字節序CPU中的存儲順序如下所示:
Big Endian
低地址 高地址
----------------------------------------------------------------------------->
| 12 | 34 | 56 | 78 |
Little Endian
低地址 高地址
----------------------------------------------------------------------------->
| 78 | 56 | 34 | 12 |
從上面兩圖可以看出,采用big endian方式存儲數據是符合我們人類的思維習慣的。
為什么要注意字節序的問題呢?你可能這么問。當然,如果你寫的程序只在單機環境下面運行,並且不和別人的程序打交道,那么你完全可以忽略字節序的存在。但是,如果你的程序要跟別人的程序產生交互呢?尤其是當你把你在微機上運算的結果運用到計算機群上去的話。
在這里我想說說兩種語言。C/C++語言編寫的程序里數據存儲順序是跟編譯平台所在的CPU相關的,而JAVA編寫的程序則唯一采用big endian方式來存儲數據。試想,如果你用C/C++語言在x86平台下編寫的程序跟別人的JAVA程序互通時會產生什么結果?就拿上面的0x12345678來說,你的程序傳遞給別人的一個數據,將指向0x12345678的指針傳給了JAVA程序,由於JAVA采取big endian方式存儲數據,很自然的它會將你的數據翻譯為0x78563412。因此,在你的C程序傳給JAVA程序之前有必要進行字節序的轉換工作。
所有網絡協議也都是采用big endian的方式來傳輸數據的。所以有時我們也會把big endian方式稱之為網絡字節序。當兩台采用不同字節序的主機通信時,在發送數據之前都必須經過字節序的轉換成為網絡字節序后再進行傳輸。ANSI C中提供了下面四個轉換字節序的宏。
一道C語言的試題:請寫一個C函數,若處理器是Big_endian的,則返回0;若是Little_endian的,則返回1。
解答:
int checkCPU()
{
{
union w
{
int a;
char b;
} c;
c.a = 1;
return (c.b == 1);
}
}
嵌入式系統開發者應該對Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU對操作數的存放方式是從低字節到高字節,而Big-endian模式對操作數的存放方式是從高字節到低字節。例如,16bit寬的數0x1234在Little- endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)為:
內存地址
存放內容
0x4000
0x34
0x400
0x12
而在Big-endian模式CPU內存中的存放方式則為:
內存地址
存放內容
0x4000
0x12
0x4001
0x34
32bit寬的數0x12345678在Little-endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)為:
內存地址
存放內容
0x4000
0x78
0x4001
0x56
0x4002
0x34
0x4003
0x12
而在Big-endian模式CPU內存中的存放方式則為:
內存地址
存放內容
0x4000
0x12
0x4001
0x34
0x4002
0x56
0x4003
0x78
聯合體union的存放順序是所有成員都從低地址開始存放,解答利用該特性,輕松地獲得了CPU對內存采用Little-endian還是Big-endian模式讀寫。
比如 int a = 0x05060708
在BIG-ENDIAN的情況下存放為:
字節號 0 1 2 3
數據 05 06 07 08
在LITTLE-ENDIAN的情況下存放為:
字節號 0 1 2 3
數據 08 07 06 05
----【轉】