深入理解Emoji(二) —— 位元組序和BOM

講故事的小黃瓜發表於2018-11-30

上篇主要了解了字符集和字符集編碼的相關知識,其中有提到位元組序的問題,這篇我們便深入探討下這方面的知識。

位元組序

位元組順序,又稱端序尾序(英語:Endianness)。在電腦科學領域中,是跨越多位元組的程式物件的儲存規則。在幾乎所有的機器上,多位元組物件都被儲存為連續的位元組序列。例如在Java中,一個int型別的變數a地址為0x100,且x的四個位元組將被儲存在儲存器的0x100, 0x101, 0x102, 0x103位置。而儲存地址內的排列則有兩個通用規則。一個多位的整數將按照其儲存地址的最低或最高位元組排列。如果最低有效位最高有效位的前面,則稱小端序;反之則稱大端序。在網路應用中,位元組序是一個必須被考慮的因素,因為不同機器型別可能採用不同標準的位元組序,所以均按照網路標準轉化。

例如假設上述變數x型別為int,位於地址0x100處,它的十六進位制為0x01234567,地址範圍為0x100~0x103位元組,其內部排列順序依賴於機器的型別。大端法從首位開始將是:0x100: 01, 0x101: 23,..。而小端法將是:0x100: 67, 0x101: 45,..

大端序

高位位元組在前,低位位元組在後,這是人類習慣的讀寫數值方法。以一個值為0x0A0B0C0D的int型別變數為例,它的記憶體為0x100~0x103,則:

記憶體地址 0x100 0x101 0x102 0x103
儲存單元 0x0A 0X0B 0X0C 0X0D

示例中,最高位位元組是0x0A 儲存在最低的記憶體地址處。下一個位元組0x0B存在後面的地址處。正類似於十六進位制位元組從左到右的閱讀順序。

小端序

低位位元組在前,高位位元組在後,現大部分計算機內部處理都是小端序。同樣以上面做例子:

記憶體地址 0x100 0x101 0x102 0x103
儲存單元 0x0D 0X0C 0X0B 0X0A

最低位位元組是0x0D 儲存在最低的記憶體地址處。後面位元組依次存在後面的地址處。

實際意義

到這裡我們可以發現,在日常開發中,如果不熟悉位元組序的情況下,在涉及位元組的讀取和解析容易出現問題,那麼,為什麼要區分大端和小端呢,統一不是更方便嗎? 其實這裡涉及一個效率的問題,計算機電路先處理低位位元組,效率比較高,因為計算都是從低位開始的。如果都是大端序,則計算時需要從高位找到低位,再從低位計算到高位,影響效率。所以,計算機的內部處理都是小端位元組序。但是我們人類還是習慣讀寫大端位元組序。所以,除了計算機的內部處理,其他的場合幾乎都是大端位元組序,比如網路傳輸和檔案儲存。

計算機處理位元組序的時候,不知道什麼是高位位元組,什麼是低位位元組。它只知道按順序讀取位元組,先讀第一個位元組,再讀第二個位元組。**如果是大端位元組序,先讀到的就是高位位元組,後讀到的就是低位位元組。小端位元組序正好相反。**只有讀取的時候,才必須區分位元組序,其他情況都不用考慮。

BOM

我們知道,UTF-16和UTF-32都是多位元組的編碼規則,那在讀取的時候必然也會涉及到位元組序的問題,計算機是通過什麼判斷編碼之後的位元組序呢,答案就是BOM。

位元組順序標記(byte-order mark,BOM)是位於碼點U+FEFF的統一碼字元的名稱。當以UTF-16或UTF-32來將UCS/統一碼字元所組成的字串編碼時,這個字元被用來標示其位元組序。它常被用來當做標示檔案是以UTF-8、UTF-16或UTF-32編碼的標記。而 FFFE 在 UCS 中是不存在的字元,所以不會出現在實際傳輸中。UCS 規範建議我們在傳輸位元組流前,先傳輸BOM標記。這樣如果接收者收到 FEFF,就表明這個位元組流是大端序的;如果收到 FFFE,就表明這個位元組流是小端序的。

不同編碼的位元組順序標記的表示

UTF-8 不需要 BOM 來表明位元組順序,但可以用 BOM 來表明編碼方式。BOM的 UTF-8 編碼是 EF BB BF。所以如果接收者收到以 EF BB BF 開頭的位元組流,就知道這是 UTF-8 編碼了。Windows 就是使用 BOM 來標記文字檔案的編碼方式的。微軟在 UTF-8 中使用 BOM 是因為這樣可以把 UTF-8 和 ASCII 等編碼明確區分開,但這樣的檔案在 Windows 之外的作業系統裡會帶來問題。

最後我們再來對比一下攜帶BOM之後UTF-16編碼所得到的結果,其中UTF-16BE代表大端序,UTF-16LE代表小端序:

UTF-16編碼

相關文章