大端模式小端模式 主机序网络序
1.?主機(jī)序
不同的CPU有不同的字節(jié)序類型這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序,這個(gè)叫做主機(jī)序。最常見的有兩種:
1.?????????Little endian:將低序字節(jié)存儲(chǔ)在起始地址。?即小端模式
2.?????????Big endian:將高序字節(jié)存儲(chǔ)在起始地址。????即大端模式
LE little-endian
最符合人的思維的字節(jié)序。地址低位存儲(chǔ)值的低位,地址高位存儲(chǔ)值的高位。怎么講是最符合人的思維的字節(jié)序,是因?yàn)閺娜说牡谝挥^感來說低位值小,就應(yīng)該放在內(nèi)存地址小的地方,也即內(nèi)存地址低位;反之,高位值就應(yīng)該放在內(nèi)存地址大的地方,也即內(nèi)存地址高位。
BE big-endian
最直觀的字節(jié)序。地址低位存儲(chǔ)值的高位,地址高位存儲(chǔ)值的低位。為什么說直觀,不要考慮對(duì)應(yīng)關(guān)系。只需要把內(nèi)存地址從左到右按照由低到高的順序?qū)懗?/span>,把值按照通常的高位到低位的順序?qū)懗?#xff0c;兩者對(duì)照,一個(gè)字節(jié)一個(gè)字節(jié)的填充進(jìn)去。
例子:在內(nèi)存中雙字0x01020304(DWORD)的存儲(chǔ)方式:
內(nèi)存地址
4000 4001 4002 4003
LE ??04 ??03 ??02 ??01
BE ??01 ??02 ??03 ??04
?
例子:1.如果我們將0x1234abcd寫入到以0x0000開始的內(nèi)存中,則結(jié)果為:
big-endian??little-endian
0x0000??0x12?????0xcd
0x0001??0x23??????0xab
0x0002??0xab????? 0x34
0x0003??0xcd??????0x12
x86系列CPU都是little-endian的字節(jié)序。
二、網(wǎng)絡(luò)序
網(wǎng)絡(luò)字節(jié)順序是TCP/IP中規(guī)定好的一種數(shù)據(jù)表示格式,它與具體的CPU類型、操作系統(tǒng)等無關(guān),從而可以保證數(shù)據(jù)在不同主機(jī)之間傳輸時(shí)能夠被正確解釋。網(wǎng)絡(luò)字節(jié)順序采用big endian排序方式。
為了進(jìn)行轉(zhuǎn)換?bsd socket提供了轉(zhuǎn)換的函數(shù)有下面四個(gè):
1.?????htons?把unsigned short類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序。
2.?????htonl?把unsigned long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序。
3.?????ntohs?把unsigned short類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序。
4.?????ntohl?把unsigned long類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序。
在使用little endian的系統(tǒng)中這些函數(shù)會(huì)把字節(jié)序進(jìn)行轉(zhuǎn)換,在使用big endian類型的系統(tǒng)中這些函數(shù)會(huì)定義成空宏。同樣在網(wǎng)絡(luò)程序開發(fā)時(shí)或是跨平臺(tái)開發(fā)時(shí),也應(yīng)該注意保證只用一種字節(jié)序,不然兩方的解釋不一樣就會(huì)產(chǎn)生bug。
注:
1.?????網(wǎng)絡(luò)與主機(jī)字節(jié)轉(zhuǎn)換函數(shù):htons ntohs htonl ntohl?(s就是short,l是long,h是host,n是network)
2.?????不同的CPU上運(yùn)行不同的操作系統(tǒng),字節(jié)序也是不同的,參見下表
處理器????操作系統(tǒng)????字節(jié)排序
Alpha????全部????Little endian
HP-PA????NT????Little endian
HP-PA????UNIX????Big endian
Intelx86????全部????Little endian <-----x86系統(tǒng)是小端字節(jié)序系統(tǒng)
Motorola680x()????全部????Big endian
MIPS????NT????Little endian
MIPS????UNIX????Big endian
PowerPC????NT????Little endian
PowerPC????非NT????Big endian??<-----PPC系統(tǒng)是大端字節(jié)序系統(tǒng)
RS/6000????UNIX????Big endian
SPARC????UNIX????Big endian
IXP1200 ARM核心????全部????Little endian
三、一些注意點(diǎn)
1.BIG-ENDIAN、LITTLE-ENDIAN跟多字節(jié)類型的數(shù)據(jù)有關(guān)的比如int,short,long型,而對(duì)單字節(jié)數(shù)據(jù)byte卻沒有影響。BIG-ENDIAN就是低位字節(jié)排放在內(nèi)存的高端,高位字節(jié)排放在內(nèi)存的低端。而LITTLE-ENDIAN正好相反。
比如 int a = 0x05060708
在BIG-ENDIAN的情況下存放為:
字節(jié)號(hào) 0 1 2 3
數(shù)據(jù) 05 06 07 08
在LITTLE-ENDIAN的情況下存放為:
字節(jié)號(hào) 0 1 2 3
數(shù)據(jù) 08 07 06 05
2.BIG-ENDIAN、LITTLE-ENDIAN、跟CPU有關(guān)的,每一種CPU不是BIG-ENDIAN就是LITTLE- ENDIAN、。IA架構(gòu)的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola處理器。這其實(shí)就是所謂的主機(jī)字節(jié)序。而網(wǎng)絡(luò)字節(jié)序是指數(shù)據(jù)在網(wǎng)絡(luò)上傳輸時(shí)是大頭還是小頭的,在Internet的網(wǎng)絡(luò)字節(jié)序是BIG-ENDIAN。所謂的JAVA字節(jié)序指的是在JAVA虛擬機(jī)中多字節(jié)類型數(shù)據(jù)的存放順序,JAVA字節(jié)序也是BIG-ENDIAN。
3.所以在用C/C++寫通信程序時(shí),在發(fā)送數(shù)據(jù)前務(wù)必用htonl和htons去把整型和短整型的數(shù)據(jù)進(jìn)行從主機(jī)字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換,而接收數(shù)據(jù)后對(duì)于整型和短整型數(shù)據(jù)則必須調(diào)用ntohl和ntohs實(shí)現(xiàn)從網(wǎng)絡(luò)字節(jié)序到主機(jī)字節(jié)序的轉(zhuǎn)換。如果通信的一方是JAVA程序、一方是 C/C++程序時(shí),則需要在C/C++一側(cè)使用以上幾個(gè)方法進(jìn)行字節(jié)序的轉(zhuǎn)換,而JAVA一側(cè),則不需要做任何處理,因?yàn)镴AVA字節(jié)序與網(wǎng)絡(luò)字節(jié)序都是 BIG-ENDIAN,只要C/C++一側(cè)能正確進(jìn)行轉(zhuǎn)換即可(發(fā)送前從主機(jī)序到網(wǎng)絡(luò)序,接收時(shí)反變換)。如果通信的雙方都是JAVA,則根本不用考慮字節(jié)序的問題了。
4.如果網(wǎng)絡(luò)上全部是PowerPC,SPARC和Motorola CPU的主機(jī)那么不會(huì)出現(xiàn)任何問題,但由于實(shí)際存在大量的IA架構(gòu)的CPU,所以經(jīng)常出現(xiàn)數(shù)據(jù)傳輸錯(cuò)誤。
5.如果程序運(yùn)行在X86架構(gòu)的PC SERVER上,發(fā)送數(shù)據(jù)的一端用C實(shí)現(xiàn)的,接收一端是用JAVA實(shí)現(xiàn)的,而發(fā)送端在發(fā)送數(shù)據(jù)前未進(jìn)行從主機(jī)字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換,這樣接收端接收到的是LITTLE-ENDIAN的數(shù)據(jù),數(shù)據(jù)解釋自然出錯(cuò)。
四、引用他人的
http://blog.csdn.net/xuyanbo2008/article/details/7458007
一、大端模式&小端模式
所謂的“大端模式”,是指數(shù)據(jù)的低位(就是權(quán)值較小的后面那幾位)保存在內(nèi)存的高地址中,而數(shù)據(jù)的高位,保存在內(nèi)存的低地址中,這樣的存儲(chǔ)模式有點(diǎn)兒類似于把數(shù)據(jù)當(dāng)作字符串順序處理:地址由小向大增加,而數(shù)據(jù)從高位往低位放;
所謂的“小端模式”,是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,而數(shù)據(jù)的高位保存在內(nèi)存的高地址中,這種存儲(chǔ)模式將地址的高低和數(shù)據(jù)位權(quán)有效地結(jié)合起來,高地址部分權(quán)值高,低地址部分權(quán)值低,和我們的邏輯方法一致。
如果將一個(gè)32位的整數(shù)0x12345678 存放到一個(gè)整型變量(int)中,這個(gè)整型變量采用大端或者小端模式在內(nèi)存中的存儲(chǔ)由下表所示。為簡(jiǎn)單起見,本文使用OP0表示一個(gè)32位數(shù)據(jù)的最高字節(jié)MSB(Most Significant Byte),使用OP3表示一個(gè)32位數(shù)據(jù)最低字節(jié)LSB(Least Significant Byte)。??
地址偏移??????? 大端模式?????? 小端模式?
0x00?????????? 12(OP0)????? 78(OP3)?
0x01?????????? 34(OP1)????? 56(OP2)?
0x02?????????? 56(OP2)????? 34(OP1)?
0x03?????????? 78(OP3)????? 12(OP0)
小端:較高的有效字節(jié)存放在較高的存儲(chǔ)器地址,較低的有效字節(jié)存放在較低的存儲(chǔ)器地址。
大端:較高的有效字節(jié)存放在較低的存儲(chǔ)器地址,較低的有效字節(jié)存放在較高的存儲(chǔ)器地址。
采用大小模式對(duì)數(shù)據(jù)進(jìn)行存放的主要區(qū)別在于在存放的字節(jié)順序,大端方式將高位存放在低地址,小端方式將高位存放在高地址。采用大端方式進(jìn)行數(shù)據(jù)存放符合人類的正常思維,而采用小端方式進(jìn)行數(shù)據(jù)存放利于計(jì)算機(jī)處理。到目前為止,采用大端或者小端進(jìn)行數(shù)據(jù)存放,其孰優(yōu)孰劣也沒有定論。
下面這段代碼可以用來測(cè)試一下你的編譯器是大端模式還是小端模式:
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址單元
x1=((char*)&x)[1]; //高地址單元
若x0=0x11,則是大端; 若x0=0x22,則是小端......
上面的程序還可以看出,數(shù)據(jù)尋址時(shí),用的是低位字節(jié)的地址
二、主機(jī)序&網(wǎng)絡(luò)序
不同的 CPU 有不同的字節(jié)序類型這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序這個(gè)叫做主機(jī)序,最常見的有兩種:?
1、Little endian :將低序字節(jié)存儲(chǔ)在起始地址?
2、Big endian :將高序字節(jié)存儲(chǔ)在起始地址
網(wǎng)絡(luò)字節(jié)順序是TCP/IP中規(guī)定好的一種數(shù)據(jù)表示格式,它與具體的CPU類型、操作系統(tǒng)等無關(guān),從而可以保證數(shù)據(jù)在不同主機(jī)之間傳輸時(shí)能夠被正確解釋。網(wǎng)絡(luò)字節(jié)順序采用big endian排序方式。
為了進(jìn)行轉(zhuǎn)換 bsd socket提供了轉(zhuǎn)換的函數(shù) 有下面四個(gè):
htons 把unsigned short類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
htonl 把unsigned long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
ntohs 把unsigned short類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
ntohl 把unsigned long類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
在使用little endian的系統(tǒng)中,這些函數(shù)會(huì)把字節(jié)序進(jìn)行轉(zhuǎn)換?
在使用big endian類型的系統(tǒng)中,這些函數(shù)會(huì)定義成空宏
同樣,在網(wǎng)絡(luò)程序開發(fā)時(shí),或是跨平臺(tái)開發(fā)時(shí),也應(yīng)該注意保證只用一種字節(jié)序,不然兩方的解釋不一樣就會(huì)產(chǎn)生BUG。
注:
1、網(wǎng)絡(luò)與主機(jī)字節(jié)轉(zhuǎn)換函數(shù):htons ntohs htonl ntohl (s 就是short l是long h是host n是network)
2、不同的CPU上運(yùn)行不同的操作系統(tǒng),字節(jié)序也是不同的,參見下表:
處理器???????????? 操作系統(tǒng)???? 字節(jié)排序
Alpha?????????????????? 全部????? Little endian
HP-PA??????????????????? NT?????? Little endian
HP-PA?????????????????? UNIX???? Big endian
Intelx86??????????????? 全部???? Little endian <-----x86系統(tǒng)是小端字節(jié)序系統(tǒng)
Motorola680x()????????? 全部??? Big endian
MIPS???????????????????? NT?????? Little endian
MIPS??????????????????? UNIX??? Big endian
PowerPC????????????????? NT???? Little endian
PowerPC???????????????? 非NT??? Big endian?? <-----PPC系統(tǒng)是大端字節(jié)序系統(tǒng)
RS/6000???????????????? UNIX??? Big endian
SPARC?????????????????? UNIX??? Big endian
IXP1200 ARM核心???????? 全部????? Little endian
下面是一個(gè)檢驗(yàn)本機(jī)字節(jié)序的簡(jiǎn)便方法:
//判斷本機(jī)的字節(jié)序
//返回true表為小段序。返回false表示為大段序
bool am_little_endian ()
{
unsigned short i=1;
return (int)*((char *)(&i)) ? true : false;
}
int main()
{
?? if(am_little_endian())
{
???????? ?? printf("本機(jī)字節(jié)序?yàn)樾《涡?\n");
}
else
{
????????? printf("本機(jī)字節(jié)序?yàn)榇蠖涡?\n");
}
??????? return 0;
}
三、入棧地址高低問題
堆棧是在內(nèi)存中指定的一段特殊存儲(chǔ)區(qū),存起始單元的地址叫棧底,當(dāng)前存儲(chǔ)單元地址叫棧頂,堆棧存儲(chǔ)區(qū)一旦指定,棧底就固定不變了,而棧頂是隨入棧、出棧操作呈動(dòng)態(tài)。而不同機(jī)型的堆棧設(shè)計(jì),有兩種情況:一是每入棧一個(gè)數(shù),棧頂?shù)刂芳?,每出棧一個(gè)數(shù),棧頂?shù)刂窚p1,即堆棧區(qū)是由內(nèi)存的低地址向高地址。另一種是每入棧一個(gè)數(shù),棧頂?shù)刂窚p1,每出棧一個(gè)數(shù),棧頂?shù)刂芳?,即堆棧區(qū)是由內(nèi)存的高地址向低地址。高地址、低地址是相對(duì)而言,即相對(duì)地址編碼的大小而言。
總結(jié)
以上是生活随笔為你收集整理的大端模式小端模式 主机序网络序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Http协议】深入理解HTTP协议
- 下一篇: 网口扫盲一:网卡初步认识