為什么我建議你從高低位和高低地址角度理解字節序?


概念

1. Big-Endian(大端模式)
Big-Endian 就是高位字節排放在內存的低地址端,低位字節排放在內存的高地址端。

2. Little-Endian(小端模式)
Little-Endian 就是低位字節排放在內存的低地址端,高位字節排放在內存的高地址端。

筆記:
大端模式又被稱作大端字節序,高端字節序;小端模式又被稱作小端字節序,低端字節序。(PS:“低端字節序”,我是在學習李忠老師的《x86實模式和保護模式》一書時了解到該詞的)

阮一峰大神的這篇《理解字節序》 對字節序的定義如下:

因為這樣的定義沒有限定場景,因此在不同場景下套用該定義常常會使我混淆,尤其在理解機器指令的時候,這個“誰前誰后”的解釋會讓我無法自洽。

從閱讀習慣看待字節序

我們從小就知道,數字是從左往右讀的,這符合人類的普遍閱讀習慣。
比如十進制數 65535,數位從高到低依次是萬,千,百,十,個。對十進制數而言,最左邊是高位數位,最右邊是低位數位

我們類比到16進制數 0x12345678,也從左往右來閱讀這個數。那么,對十六進制數而言,最左邊就是高位字節,最右邊是低位字節

從內存地址的角度看字節序

首先,你可能需要對內存有一些基本的認識:

  1. 一個內存單元可以存儲一個字節的內容,因此內存單元也常常被稱為字節單元。
  2. 一個內存單元可以存儲8個比特,即8個二進制數。但是,如果換算成16進制,一個內存單元僅能容納2個16進制數。

如圖所示,我們在畫內存示意圖的時候,我們用一個綠色矩形表示一個內存單元,每一個內存單元都有一個內存地址,方便計算機的處理器找到這塊內存單元。
另外,我們也習慣於內存地址將低地址端放在下面,高地址端放在上面。

這個習慣,我猜測可能與古人建房子的習慣類似,所謂“萬丈高樓平地起”,最先建的總是低層,然后再建高層。高層究竟建多高,這個總是不斷發展和變化的,但是最底層總是從零開始,這個是相對穩定的。


還是以十六進制數 0x12345678 為例,當它以大端字節序存儲在內存中時,低地址端 0x0000 存儲該數的高位字節 0x12;高地址端 0x0003 存儲的是該數的低位字節 0x78


0x12345678小端字節序存儲在內存中時,低地址端 0x0000 存儲該數的低位字節 0x78;高地址端 0x0003 存儲的是該數的高位字節 0x12

你看,如果我用內存示意圖的這種上下分布的結構來表示字節序,“誰在前誰在后”這個理論就失效了~

從處理器看字節序

在學習李忠老師的《x86實模式和保護模式》時,我了解到 Intel 8086 處理器(經典的16位處理器)是采用小端字節序。Intel 公司后續的32位x86處理器和64位x64處理器采用的也依然是小端字節序。

比如下面有一條簡單的傳送指令代碼:

mov ax, 0x2000

這條 mov 指令的意思是將立即數 0x2000 傳送到 CPU 內的通用寄存器 ax 中。
這條指令在我配備 Intel x64 處理器的 Windows 系統電腦上,編譯出來的機器碼是 B80020

匯編程序編譯出來的文件是二進制文件,它的內容是0或者1,當使用 HexView.exe 用十六進制的方式來查看文件時,就有了如下圖所示:

B8是機器指令的操作碼,0x2000 的低位字節存儲在二進制文件的低地址端,高位字節存儲在二進制文件的高地址端。

這條指令所在的程序,如果從磁盤中被加載到內存中:

此時,指令在內存中仍然保持着小端字節序存儲。接下來,如果指令執行,就要將內存中的內容放入到通用寄存器 ax 中了。

通常,寄存器的閱讀順序一般是從左到右。左邊是高位字節,右邊是低位字節。

也就是說指令執行之后,最終在寄存器 ax 中顯示的結果和我們源程序中的值是一樣的,都是 0x2000

從網絡傳輸的角度看字節序

在網絡上傳輸數據時,由於數據傳輸的兩端對應不同的硬件平台,采用的存儲字節順序可能不一致。所以在TCP/IP協議規定了在網絡上必須采用網絡字節順序,也就是大端模式

  • 對於char型數據只占一個字節,無所謂大端和小端。
  • 而對於非char類型數據,必須在數據發送到網絡上之前將其轉換成大端模式。

接收網絡數據時按符合接受主機的環境接收。

簡而言之,網絡字節序是大端字節序。

我們常用 Wireshark 這款軟件抓取 TCP 報文,以下是我抓取到的三次握手中的 SYN 報文的抓包情況:

圖中的 0000, 0010, 0020, 0030, 0040 表示的是16進制數。

我們通常編寫和閱讀的電腦文件中,總是習慣於從上到下,從左到右。此時低地址在左邊或者在上邊,高地址在右邊或者下邊。

十進制數 40190 等於十六進制數 0x9cfe,十進制數 5222 等於十六進制數 0x1466。

我們聚焦抓包的內容的第 4 行,即起始地址為 0x0040,最后一個地址為 0x004f

  • 0x9cfe 的高位字節 0x9c 保存在低地址端 0x0045,低位字節是 0xfe 保存在高地址端 0x0046
  • 0x1466 的高位字節 0x14 保存在低地址端 0x0047,低位字節是 0x66 保存在高地址端 0x0048

總結

可能你不了解內存,不清楚寄存器,不明白編譯,但是你可以記住

“低低低,低高高”

  1. 低位字節排放在內存的低地址端,就是低端字節序。

  2. 低位字節排放在內存的高地址端,就是高端字節序。

  3. 高端字節序就是大端字節序;低端字節序就是小端字節序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM