網路程式設計,位元組序肯定是需要牢記的乙個知識點了。
不同的 cpu 有不同的位元組序型別 這些位元組序是指整數在記憶體中儲存的順序 這個叫做主機序
最常見的有兩種
1 . little endian :將低序位元組儲存在起始位址
2 . big endian :將高序位元組儲存在起始位址
le little-endian
最符合人的思維的位元組序
位址低位儲存值的低位
位址高位儲存值的高位
怎麼講是最符合人的思維的位元組序,是因為從人的第一觀感來說
低位值小,就應該放在記憶體位址小的地方,也即記憶體位址低位
反之,高位值就應該放在記憶體位址大的地方,也即記憶體位址高位
be big-endian
最直觀的位元組序
位址低位儲存值的高位
位址高位儲存值的低位
為什麼說直觀,不要考慮對應關係
只需要把記憶體位址從左到右按照由低到高的順序寫出
把值按照通常的高位到低位的順序寫出
兩者對照,乙個位元組乙個位元組的填充進去
例子:在記憶體中雙字 0x01020304(dword) 的儲存方式
記憶體位址
4000 4001 4002 4003
le 04 03 02 01
be 01 02 03 04
例子:如果我們將 0x1234abcd 寫入到以 0x0000 開始的記憶體中,則結果為
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x23 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
x86 系列 cpu 都是 little-endian 的位元組序 .
網路位元組順序是 tcp/ip 中規定好的一種資料表示格式,它與具體的 cpu 型別、作業系統等無關,從而可以保證資料在不同主機之間傳輸時能夠被正確解釋。網路位元組順序採用 big endian 排序方式。
為了進行轉換 bsd socket 提供了轉換的函式 有下面四個
htons 把 unsigned short 型別從主機序轉換到網路序
htonl 把 unsigned long 型別從主機序轉換到網路序
ntohs 把 unsigned short 型別從網路序轉換到主機序
ntohl 把 unsigned long 型別從網路序轉換到主機序
在使用 little endian 的系統中 這些函式會把位元組序進行轉換
在使用 big endian 型別的系統中 這些函式會定義成空巨集
同樣 在網路程式開發時 或是跨平台開發時 也應該注意保證只用一種位元組序 不然兩方的解釋不一樣就會產生 bug.
注: 1 、網路與主機位元組轉換函式 :htons ntohs htonl ntohl (s 就是 short l 是 long h 是 host n 是 network)
2 、不同的 cpu 上執行不同的作業系統,位元組序也是不同的,參見下表。
處理器 作業系統 位元組排序
alpha 全部 little endian
hp-pa nt little endian
hp-pa unix big endian
intelx86 全部 little endian <-----x86 系統是小端位元組序系統
motorola680x() 全部 big endian
mips nt little endian
mips unix big endian
powerpc nt little endian
powerpc 非 nt big endian <-----ppc 系統是大端位元組序系統
rs/6000 unix big endian
sparc unix big endian
ixp1200 arm 核心 全部 little endian
2. 一、位元組序定義
位元組序,顧名思義位元組的順序,再多說兩句就是大於乙個位元組型別的資料在記憶體中的存放順序(乙個位元組的資料當然就無需談順序的問題了)。
其實大部分人在實際的開發中都很少會直接和位元組序打交道。唯有在跨平台以及網路程式中位元組序才是乙個應該被考慮的問題。
在所有的介紹位元組序的文章中都會提到位元組序分為兩類:big-endian和little-endian。引用標準的big-endian和little-endian的定義如下:
a) little-endian就是低位位元組排放在記憶體的低位址端,高位位元組排放在記憶體的高位址端。
b) big-endian就是高位位元組排放在記憶體的低位址端,低位位元組排放在記憶體的高位址端。
c) 網路位元組序:4個位元組的32 bit值以下面的次序傳輸:首先是0~7bit,其次8~15bit,然後16~23bit,最後是24~31bit。這種傳輸次序稱作大端位元組序。由於 tcp/ip首部中所有的二進位制整數在網路中傳輸時都要求以這種次序,因此它又稱作網路位元組序。比如,乙太網頭部中2位元組的「 乙太網幀型別」,表示後面資料的型別。對於arp請求或應答的乙太網幀型別 來說,在網路傳輸時,傳送的順序是0x08,0x06。在記憶體中的映象如下圖所示:
棧底 (高位址)
---------------
0x06 -- 低位
0x08 -- 高位
---------------
棧頂 (低位址)
該字段的值為0x0806。按照大端方式存放在記憶體中。
二、高/低位址與高低位元組
首先我們要知道我們c程式映像中記憶體的空間布局情況:在《c專家程式設計》中或者《unix環境高階程式設計》中有關於記憶體空間布局情況的說明,大致如下圖:
----------------------- 最高記憶體位址 0xffffffff
| 棧底
.. 棧.棧頂
-----------------------||
\|/
null (空洞)
/|\|
|-----------------------
堆-----------------------
未初始化的資料
----------------(統稱資料段)
初始化的資料
-----------------------
正文段(**段)
----------------------- 最低記憶體位址 0x00000000
以上圖為例如果我們在棧上分配乙個unsigned char buf[4],那麼這個陣列變數在棧上是如何布局的呢[注1]?看下圖:
棧底 (高位址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低位址)
現在我們弄清了高低位址,接著來弄清高/低位元組,如果我們有乙個32位無符號整型0x12345678(呵呵,恰好是把上面的那4個位元組buf看成乙個整型),那麼高位是什麼,低位又是什麼呢?其實很簡單。在十進位制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進製也是如此。就拿 0x12345678來說,從高位到低位的位元組依次是0x12、0x34、0x56和0x78。
高低位址和高低位元組都弄清了。我們再來回顧一下big-endian和little-endian的定義,並用圖示說明兩種位元組序:
以unsigned int value = 0x12345678為例,分別看看在兩種位元組序下其儲存情況,我們可以用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) -- 低位
---------------
棧頂 (低位址)
在現有的平台上intel的x86採用的是little-endian,而像sun的sparc採用的就是big-endian。
三、例子
嵌入式系統開發者應該對little-endian和big-endian模式非常了解。採用little-endian模式的cpu對運算元的存放方式是從低位元組到高位元組,而big-endian模式對運算元的存放方式是從高位元組到低位元組。
記憶體位址 存放內容
0x4001 0x12
0x4000 0x34
而在big-endian模式cpu記憶體中的存放方式則為:
記憶體位址 存放內容
0x4001 0x34
0x4000 0x12
記憶體位址 存放內容
0x4003 0x12
0x4002 0x34
0x4001 0x56
0x4000 0x78
而在big-endian模式cpu記憶體中的存放方式則為:
記憶體位址 存放內容
0x4003 0x78
0x4002 0x56
0x4001 0x34
0x4000 0x12
主機位元組序和網路位元組序(大端序,小端序,網路序)
根據cpu的不同我們可以把主機位元組序在記憶體中儲存的順序叫做主機序,也就是我們常說的,大端機和小端機。我們經常看到的有兩種 1.小端機 記憶體中以小端序儲存的機器 將低位元組序儲存在開始的位址 及記憶體較小的記憶體 舉個例子 我們將記憶體從左到右排列 在記憶體中存放0x01020304 2000 ...
socket網路位元組序以及大端序小端序
不同cpu中,4位元組整數1在記憶體空間的儲存方式是不同的。4位元組整數1可用2進製表示如下 00000000 00000000 00000000 00000001 有些cpu以上面的順序儲存到記憶體,另外一些cpu則以倒序儲存,如下所示 00000001 00000000 00000000 000...
位元組 字典序
給定整數n和m,將1到n的這n個整數按字典序排列之後,求其中的第m個數。對於n 11,m 4,按字典序排列依次為1,10 11,2 3,4 5,6 7,8 9,因此第4個數是2.對於n 200,m 25,按字典序排列依次為1 10100 101102 103104 105106 107108 109...