大頭小頭 字節序

字節序的問題涉及硬件架構,目前主要是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列採用big endian方式存儲數據,而x86系列則採用little endian方式存儲數據。那麼究竟什麼是big endian,什麼又是little endian呢?

 

爲方便理解,摘了INTER手冊中的一張圖。呵呵。

 

 

字節順序是指佔內存多於一個字節類型的數據在內存中的存放順序,通常有小端、大端兩種字節順序。小端字節序指低字節數據存放在內存低地址處,高字節數據存放在內存高地址處;大端字節序是高字節數據存放在低地址處,低字節數據存放在高地址處

 

基於IAX86平臺的PC機是小端字節序的,而有的嵌入式平臺則是大端字節序的。因而對WORD/DWORD/QWORD等多於1字節類型的數據,在這些嵌入式平臺上應該變換其存儲順序。通常我們認爲,在空中傳輸的字節的順序即網絡字節序爲標準順序,考慮到與協議的一致以及與同類其它平臺產品的互通,在程序中發數據包時,將主機字節序轉換爲網絡字節序,收數據包處將網絡字節序轉換爲主機字節序。

 

用文字說明可能比較抽象,下面用圖像加以說明。比如數字0x12345678在兩種不同字節序CPU中的存儲順序如下所示:

對於0x12345678,

Little endian:高地址<------->低:存儲數據0x12 0x34 0x56 0x78

Big endian:   高地址<------->低:存儲數據0x78 0x56 0x34 0x12

爲什麼要注意字節序的問題呢?當然,如果你寫的程序只在單機環境下面運行,並且不和別人的程序打交道,那麼你完全可以忽略字節序的存在。但是,如果你的程序要跟別人的程序產生交互呢?C/C++語言編寫的程序裏數據存儲順序是跟編譯平臺所在的CPU相關的,而JAVA編寫的程序則唯一採用big endian方式來存儲數據。試想,如果你用C/C++語言在x86平臺下編寫的程序跟別人的JAVA程序互通時會產生什麼結果?就拿上面的0x12345678來說,你的程序傳遞給別人的一個數據,將指向0x12345678的指針傳給了JAVA程序,由於JAVA採取big endian方式存儲數據,很自然的它會將你的數據翻譯爲0x78563412。因此,在你的C程序傳給JAVA程序之前有必要進行字節序的轉換工作。 

 

所有網絡協議也都是採用big endian的方式來傳輸數據的。所以有時我們也會把big endian方式稱之爲網絡字節序。當兩臺採用不同字節序的主機通信時,在發送數據之前都必須經過字節序的轉換成爲網絡字節序後再進行傳輸。 
判斷小端還是大端規則的方法:
int x = 1;
if(*(char *)&x == 1)    //取x指針強制轉換爲char*類型再取值,此時取到的值是int最低字節值
    printf("little-endian/n");
else
    printf("big-endian/n"); 

另外補充:

1.BIG-ENDIAN、LITTLE-ENDIAN是跟CPU有關的,每一種CPU不是BIG-ENDIAN就是LITTLE-ENDIAN。IA架構的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola處理器。這其實就是所謂的主機字節序。而網絡字節序是指數據在網絡上傳輸時是大頭還是小頭的,在Internet的網絡字節序是BIG-ENDIAN。所謂的JAVA字節序指的是在JAVA虛擬機中多字節類型數據的存放順序,JAVA字節序也是BIG-ENDIAN。

2.所以在用C/C++寫通信程序時,在發送數據前務必用htonl和htons去把整型和短整型的數據進行從主機字節序到網絡字節序的轉換,而接收數據後對於整型和短整型數據則必須調用ntohl和ntohs實現從網絡字節序到主機字節序的轉換。如果通信的一方是JAVA程序、一方是C/C++程序時,則需要在C/C++一側使用以上幾個方法進行字節序的轉換,而JAVA一側,則不需要做任何處理,因爲JAVA字節序與網絡字節序都是BIG-ENDIAN,只要C/C++一側能正確進行轉換即可(發送前從主機序到網絡序,接收時反變換)。如果通信的雙方都是JAVA,則根本不用考慮字節序的問題了。  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章