2011知識(shí)點(diǎn) - 大端模式與小端模式、網(wǎng)絡(luò)字節(jié)順序與主機(jī)字節(jié)順序 (經(jīng)典)[zz]
大端模式與小端模式
一、概念及詳解
在各種體系的計(jì)算機(jī)中通常采用的字節(jié)存儲(chǔ)機(jī)制主要有兩種: big-endian和little-endian,即大端模式和小端模式。
先回顧兩個(gè)關(guān)鍵詞,MSB和LSB:
MSB:Most Significant Bit ------- 最高有效位
LSB:Least Significant Bit ------- 最低有效位
大端模式(big-edian)
big-endian:MSB存放在最低端的地址上。
舉例,雙字節(jié)數(shù)0x1234以big-endian的方式存在起始地址0x00002000中:
| data |<-- address
| 0x12 |<-- 0x00002000
| 0x34 |<-- 0x00002001
在Big-Endian中,對(duì)于bit序列中的序號(hào)編排方式如下(以雙字節(jié)數(shù)0x8B8A為例):
bit | 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15
------MSB----------------------------------LSB
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+--------------------------------------------+
= 0x8 B 8 A
小端模式(little-endian)
little-endian:LSB存放在最低端的地址上。
舉例,雙字節(jié)數(shù)0x1234以little-endian的方式存在起始地址0x00002000中:
| data |<-- address
| 0x34 |<-- 0x00002000
| 0x12 |<-- 0x00002001
在Little-Endian中,對(duì)于bit序列中的序號(hào)編排和Big-Endian剛好相反,其方式如下(以雙字節(jié)數(shù)0x8B8A為例):
bit | 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0
------MSB-----------------------------------LSB
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+---------------------------------------------+
= 0x8 B 8 A
二、數(shù)組在大端小端情況下的存儲(chǔ):
以u(píng)nsigned int value = 0x12345678為例,分別看看在兩種字節(jié)序下其存儲(chǔ)情況,我們可以用unsigned char buf[4]來表示value:
Big-Endian: 低地址存放高位,如下:
高地址
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
低地址
Little-Endian: 低地址存放低位,如下:
高地址
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
低地址
三、大端小端轉(zhuǎn)換方法:
Big-Endian轉(zhuǎn)換成Little-Endian如下:
#define BigtoLittle16(A) ((((uint16)(A) & 0xff00) >> 8) | \
(((uint16)(A) & 0x00ff) << 8))
#define BigtoLittle32(A) ((((uint32)(A) & 0xff000000) >> 24) | \
(((uint32)(A) & 0x00ff0000) >> 8) | \
(((uint32)(A) & 0x0000ff00) << 8) | \
(((uint32)(A) & 0x000000ff) << 24))
四、大端小端檢測(cè)方法:
如何檢查處理器是big-endian還是little-endian?
聯(lián)合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕松地獲得了CPU對(duì)內(nèi)存采用Little-endian還是Big-endian模式讀寫。
int checkCPUendian()
{
union
{
unsigned int a;
unsigned char b;
}c;
c.a = 1;
return (c.b == 1);
}
/*return 1 : little-endian, return 0:big-endian*/
網(wǎng)絡(luò)字節(jié)順序
1、字節(jié)內(nèi)的比特位不受這種順序的影響
比如一個(gè)字節(jié) 1000 0000 (或表示為十六進(jìn)制 80H)不管是什么順序其內(nèi)存中的表示法都是這樣。
2、大于1個(gè)字節(jié)的數(shù)據(jù)類型才有字節(jié)順序問題
比如 Byte A,這個(gè)變量只有一個(gè)字節(jié)的長度,所以根據(jù)上一條沒有字節(jié)順序問題。所以字節(jié)順序是“字節(jié)之間的相對(duì)順序”的意思。
3、大于1個(gè)字節(jié)的數(shù)據(jù)類型的字節(jié)順序有兩種
比如 short B,這是一個(gè)兩字節(jié)的數(shù)據(jù)類型,這時(shí)就有字節(jié)之間的相對(duì)順序問題了。
網(wǎng)絡(luò)字節(jié)順序是“所見即所得”的順序。而Intel類型的CPU的字節(jié)順序與此相反。
比如上面的 short B=0102H(十六進(jìn)制,每兩位表示一個(gè)字節(jié)的寬度)。所見到的是“0102”,按一般數(shù)學(xué)常識(shí),數(shù)軸從左到右的方向增加,即內(nèi)存地址從左到右增加的話,在內(nèi)存中這個(gè) short B的字節(jié)順序是:
01 02
這就是網(wǎng)絡(luò)字節(jié)順序。所見到的順序和在內(nèi)存中的順序是一致的!
而相反的字節(jié)順序就不同了,其在內(nèi)存中的順序?yàn)椋?2 01
假設(shè)通過抓包得到網(wǎng)絡(luò)數(shù)據(jù)的兩個(gè)字節(jié)流為:01 02
如果這表示兩個(gè) Byte類型的變量,那么自然不需要考慮字節(jié)順序的問題。
如果這表示一個(gè) short 變量,那么就需要考慮字節(jié)順序問題。根據(jù)網(wǎng)絡(luò)字節(jié)順序“所見即所得”的規(guī)則,這個(gè)變量的值就是:0102
假設(shè)本地主機(jī)是Intel類型的,那么要表示這個(gè)變量,有點(diǎn)麻煩:
定義變量 short X,
字節(jié)流地址為:pt,按順序讀取內(nèi)存是為
x=*((short*)pt);
那么X的內(nèi)存順序當(dāng)然是 01 02
按非“所見即所得”的規(guī)則,這個(gè)內(nèi)存順序和看到的一樣顯然是不對(duì)的,所以要把這兩個(gè)字節(jié)的位置調(diào)換。
調(diào)換的方法可以自己定義,但用已經(jīng)有的API還是更為方便。
網(wǎng)絡(luò)字節(jié)順序與主機(jī)字節(jié)順序
NBO與HBO 網(wǎng)絡(luò)字節(jié)順序NBO(Network Byte Order):按從高到低的順序存儲(chǔ),在網(wǎng)絡(luò)上使用統(tǒng)一的網(wǎng)絡(luò)字節(jié)順序,可以避免兼容性問題。主機(jī)字節(jié)順序(HBO,Host Byte Order):不同的機(jī)器HBO不相同,與CPU設(shè)計(jì)有關(guān)計(jì)算機(jī)數(shù)據(jù)存儲(chǔ)有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先。Internet上數(shù)據(jù)以高位字節(jié)優(yōu)先順序在網(wǎng)絡(luò)上傳輸,所以對(duì)于在內(nèi)部是以低位字節(jié)優(yōu)先方式存儲(chǔ)數(shù)據(jù)的機(jī)器,在Internet上傳輸數(shù)據(jù)時(shí)就需要進(jìn)行轉(zhuǎn)換。
htonl()
簡述:
將主機(jī)的無符號(hào)長整形數(shù)轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序。
#include <winsock.h>
u_long PASCAL FAR htonl( u_long hostlong);
hostlong:主機(jī)字節(jié)順序表達(dá)的32位數(shù)。
注釋:
本函數(shù)將一個(gè)32位數(shù)從主機(jī)字節(jié)順序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序。
返回值:
htonl()返回一個(gè)網(wǎng)絡(luò)字節(jié)順序的值。
inet_ntoa()
簡述:
將網(wǎng)絡(luò)地址轉(zhuǎn)換成“.”點(diǎn)隔的字符串格式。
#include <winsock.h>
char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
in:一個(gè)表示Internet主機(jī)地址的結(jié)構(gòu)。
注釋:
本函數(shù)將一個(gè)用in參數(shù)所表示的Internet地址結(jié)構(gòu)轉(zhuǎn)換成以“.” 間隔的諸如“a.b.c.d”的字符串形式。請(qǐng)注意inet_ntoa()返回的字符串存放在WINDOWS套接口實(shí)現(xiàn)所分配的內(nèi)存中。應(yīng)用程序不應(yīng)假設(shè)該內(nèi)存是如何分配的。在同一個(gè)線程的下一個(gè)WINDOWS套接口調(diào)用前,數(shù)據(jù)將保證是有效。
返回值:
若無錯(cuò)誤發(fā)生,inet_ntoa()返回一個(gè)字符指針。否則的話,返回NULL。其中的數(shù)據(jù)應(yīng)在下一個(gè)WINDOWS套接口調(diào)用前復(fù)制出來。
網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)有的和本地字節(jié)存儲(chǔ)順序一致,而有的則截然不同,為了數(shù)據(jù)的一致性,就要把本地的數(shù)據(jù)轉(zhuǎn)換成網(wǎng)絡(luò)上使用的格式,然后發(fā)送出去,接收的時(shí)候也是一樣的,經(jīng)過轉(zhuǎn)換然后才去使用這些數(shù)據(jù),基本的庫函數(shù)中提供了這樣的可以進(jìn)行字節(jié)轉(zhuǎn)換的函數(shù),如和htons( ) htonl( ) ntohs( ) ntohl( ),這里n表示network,h表示host,htons( ) htonl( )用于本地字節(jié)向網(wǎng)絡(luò)字節(jié)轉(zhuǎn)換的場(chǎng)合,s表示short,即對(duì)2字節(jié)操作,l表示long即對(duì)4字節(jié)操作。同樣ntohs( )ntohl( )用于網(wǎng)絡(luò)字節(jié)向本地格式轉(zhuǎn)換的場(chǎng)合。
一、概念及詳解
在各種體系的計(jì)算機(jī)中通常采用的字節(jié)存儲(chǔ)機(jī)制主要有兩種: big-endian和little-endian,即大端模式和小端模式。
先回顧兩個(gè)關(guān)鍵詞,MSB和LSB:
MSB:Most Significant Bit ------- 最高有效位
LSB:Least Significant Bit ------- 最低有效位
大端模式(big-edian)
big-endian:MSB存放在最低端的地址上。
舉例,雙字節(jié)數(shù)0x1234以big-endian的方式存在起始地址0x00002000中:
| data |<-- address
| 0x12 |<-- 0x00002000
| 0x34 |<-- 0x00002001
在Big-Endian中,對(duì)于bit序列中的序號(hào)編排方式如下(以雙字節(jié)數(shù)0x8B8A為例):
bit | 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15
------MSB----------------------------------LSB
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+--------------------------------------------+
= 0x8 B 8 A
小端模式(little-endian)
little-endian:LSB存放在最低端的地址上。
舉例,雙字節(jié)數(shù)0x1234以little-endian的方式存在起始地址0x00002000中:
| data |<-- address
| 0x34 |<-- 0x00002000
| 0x12 |<-- 0x00002001
在Little-Endian中,對(duì)于bit序列中的序號(hào)編排和Big-Endian剛好相反,其方式如下(以雙字節(jié)數(shù)0x8B8A為例):
bit | 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0
------MSB-----------------------------------LSB
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+---------------------------------------------+
= 0x8 B 8 A
二、數(shù)組在大端小端情況下的存儲(chǔ):
以u(píng)nsigned int value = 0x12345678為例,分別看看在兩種字節(jié)序下其存儲(chǔ)情況,我們可以用unsigned char buf[4]來表示value:
Big-Endian: 低地址存放高位,如下:
高地址
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
低地址
Little-Endian: 低地址存放低位,如下:
高地址
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
低地址
三、大端小端轉(zhuǎn)換方法:
Big-Endian轉(zhuǎn)換成Little-Endian如下:
#define BigtoLittle16(A) ((((uint16)(A) & 0xff00) >> 8) | \
(((uint16)(A) & 0x00ff) << 8))
#define BigtoLittle32(A) ((((uint32)(A) & 0xff000000) >> 24) | \
(((uint32)(A) & 0x00ff0000) >> 8) | \
(((uint32)(A) & 0x0000ff00) << 8) | \
(((uint32)(A) & 0x000000ff) << 24))
四、大端小端檢測(cè)方法:
如何檢查處理器是big-endian還是little-endian?
聯(lián)合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕松地獲得了CPU對(duì)內(nèi)存采用Little-endian還是Big-endian模式讀寫。
int checkCPUendian()
{
union
{
unsigned int a;
unsigned char b;
}c;
c.a = 1;
return (c.b == 1);
}
/*return 1 : little-endian, return 0:big-endian*/
網(wǎng)絡(luò)字節(jié)順序
1、字節(jié)內(nèi)的比特位不受這種順序的影響
比如一個(gè)字節(jié) 1000 0000 (或表示為十六進(jìn)制 80H)不管是什么順序其內(nèi)存中的表示法都是這樣。
2、大于1個(gè)字節(jié)的數(shù)據(jù)類型才有字節(jié)順序問題
比如 Byte A,這個(gè)變量只有一個(gè)字節(jié)的長度,所以根據(jù)上一條沒有字節(jié)順序問題。所以字節(jié)順序是“字節(jié)之間的相對(duì)順序”的意思。
3、大于1個(gè)字節(jié)的數(shù)據(jù)類型的字節(jié)順序有兩種
比如 short B,這是一個(gè)兩字節(jié)的數(shù)據(jù)類型,這時(shí)就有字節(jié)之間的相對(duì)順序問題了。
網(wǎng)絡(luò)字節(jié)順序是“所見即所得”的順序。而Intel類型的CPU的字節(jié)順序與此相反。
比如上面的 short B=0102H(十六進(jìn)制,每兩位表示一個(gè)字節(jié)的寬度)。所見到的是“0102”,按一般數(shù)學(xué)常識(shí),數(shù)軸從左到右的方向增加,即內(nèi)存地址從左到右增加的話,在內(nèi)存中這個(gè) short B的字節(jié)順序是:
01 02
這就是網(wǎng)絡(luò)字節(jié)順序。所見到的順序和在內(nèi)存中的順序是一致的!
而相反的字節(jié)順序就不同了,其在內(nèi)存中的順序?yàn)椋?2 01
假設(shè)通過抓包得到網(wǎng)絡(luò)數(shù)據(jù)的兩個(gè)字節(jié)流為:01 02
如果這表示兩個(gè) Byte類型的變量,那么自然不需要考慮字節(jié)順序的問題。
如果這表示一個(gè) short 變量,那么就需要考慮字節(jié)順序問題。根據(jù)網(wǎng)絡(luò)字節(jié)順序“所見即所得”的規(guī)則,這個(gè)變量的值就是:0102
假設(shè)本地主機(jī)是Intel類型的,那么要表示這個(gè)變量,有點(diǎn)麻煩:
定義變量 short X,
字節(jié)流地址為:pt,按順序讀取內(nèi)存是為
x=*((short*)pt);
那么X的內(nèi)存順序當(dāng)然是 01 02
按非“所見即所得”的規(guī)則,這個(gè)內(nèi)存順序和看到的一樣顯然是不對(duì)的,所以要把這兩個(gè)字節(jié)的位置調(diào)換。
調(diào)換的方法可以自己定義,但用已經(jīng)有的API還是更為方便。
網(wǎng)絡(luò)字節(jié)順序與主機(jī)字節(jié)順序
NBO與HBO 網(wǎng)絡(luò)字節(jié)順序NBO(Network Byte Order):按從高到低的順序存儲(chǔ),在網(wǎng)絡(luò)上使用統(tǒng)一的網(wǎng)絡(luò)字節(jié)順序,可以避免兼容性問題。主機(jī)字節(jié)順序(HBO,Host Byte Order):不同的機(jī)器HBO不相同,與CPU設(shè)計(jì)有關(guān)計(jì)算機(jī)數(shù)據(jù)存儲(chǔ)有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先。Internet上數(shù)據(jù)以高位字節(jié)優(yōu)先順序在網(wǎng)絡(luò)上傳輸,所以對(duì)于在內(nèi)部是以低位字節(jié)優(yōu)先方式存儲(chǔ)數(shù)據(jù)的機(jī)器,在Internet上傳輸數(shù)據(jù)時(shí)就需要進(jìn)行轉(zhuǎn)換。
htonl()
簡述:
將主機(jī)的無符號(hào)長整形數(shù)轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序。
#include <winsock.h>
u_long PASCAL FAR htonl( u_long hostlong);
hostlong:主機(jī)字節(jié)順序表達(dá)的32位數(shù)。
注釋:
本函數(shù)將一個(gè)32位數(shù)從主機(jī)字節(jié)順序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)順序。
返回值:
htonl()返回一個(gè)網(wǎng)絡(luò)字節(jié)順序的值。
inet_ntoa()
簡述:
將網(wǎng)絡(luò)地址轉(zhuǎn)換成“.”點(diǎn)隔的字符串格式。
#include <winsock.h>
char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
in:一個(gè)表示Internet主機(jī)地址的結(jié)構(gòu)。
注釋:
本函數(shù)將一個(gè)用in參數(shù)所表示的Internet地址結(jié)構(gòu)轉(zhuǎn)換成以“.” 間隔的諸如“a.b.c.d”的字符串形式。請(qǐng)注意inet_ntoa()返回的字符串存放在WINDOWS套接口實(shí)現(xiàn)所分配的內(nèi)存中。應(yīng)用程序不應(yīng)假設(shè)該內(nèi)存是如何分配的。在同一個(gè)線程的下一個(gè)WINDOWS套接口調(diào)用前,數(shù)據(jù)將保證是有效。
返回值:
若無錯(cuò)誤發(fā)生,inet_ntoa()返回一個(gè)字符指針。否則的話,返回NULL。其中的數(shù)據(jù)應(yīng)在下一個(gè)WINDOWS套接口調(diào)用前復(fù)制出來。
網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)有的和本地字節(jié)存儲(chǔ)順序一致,而有的則截然不同,為了數(shù)據(jù)的一致性,就要把本地的數(shù)據(jù)轉(zhuǎn)換成網(wǎng)絡(luò)上使用的格式,然后發(fā)送出去,接收的時(shí)候也是一樣的,經(jīng)過轉(zhuǎn)換然后才去使用這些數(shù)據(jù),基本的庫函數(shù)中提供了這樣的可以進(jìn)行字節(jié)轉(zhuǎn)換的函數(shù),如和htons( ) htonl( ) ntohs( ) ntohl( ),這里n表示network,h表示host,htons( ) htonl( )用于本地字節(jié)向網(wǎng)絡(luò)字節(jié)轉(zhuǎn)換的場(chǎng)合,s表示short,即對(duì)2字節(jié)操作,l表示long即對(duì)4字節(jié)操作。同樣ntohs( )ntohl( )用于網(wǎng)絡(luò)字節(jié)向本地格式轉(zhuǎn)換的場(chǎng)合。
posted on 2011-09-21 13:03 simplyzhao 閱讀(233) 評(píng)論(0) 編輯 收藏 引用 所屬分類: R_找工復(fù)習(xí)2011