上篇主要了解了字符集和字符集編碼的相關(guān)知識(shí)浙宜,其中有提到字節(jié)序的問題平夜,這篇我們便深入探討下這方面的知識(shí)线脚。
字節(jié)序
字節(jié)順序那婉,又稱端序或尾序(英語:Endianness)板甘。在計(jì)算機(jī)科學(xué)領(lǐng)域中,是跨越多字節(jié)的程序?qū)ο蟮拇鎯?chǔ)規(guī)則详炬。在幾乎所有的機(jī)器上虾啦,多字節(jié)對(duì)象都被存儲(chǔ)為連續(xù)的字節(jié)序列。例如在Java中,一個(gè)int類型的變量a地址為0x100傲醉,且x
的四個(gè)字節(jié)將被存儲(chǔ)在存儲(chǔ)器的0x100, 0x101, 0x102, 0x103
位置。而存儲(chǔ)地址內(nèi)的排列則有兩個(gè)通用規(guī)則呻率。一個(gè)多位的整數(shù)將按照其存儲(chǔ)地址的最低或最高字節(jié)排列硬毕。如果最低有效位在最高有效位的前面,則稱小端序礼仗;反之則稱大端序吐咳。在網(wǎng)絡(luò)應(yīng)用中,字節(jié)序是一個(gè)必須被考慮的因素元践,因?yàn)椴煌瑱C(jī)器類型可能采用不同標(biāo)準(zhǔn)的字節(jié)序韭脊,所以均按照網(wǎng)絡(luò)標(biāo)準(zhǔn)轉(zhuǎn)化。
例如假設(shè)上述變量x
類型為int
单旁,位于地址0x100
處沪羔,它的十六進(jìn)制為0x01234567
,地址范圍為0x100~0x103
字節(jié)象浑,其內(nèi)部排列順序依賴于機(jī)器的類型蔫饰。大端法從首位開始將是:0x100: 01, 0x101: 23,..
。而小端法將是:0x100: 67, 0x101: 45,..
愉豺。
大端序
高位字節(jié)在前篓吁,低位字節(jié)在后,這是人類習(xí)慣的讀寫數(shù)值方法蚪拦。以一個(gè)值為0x0A0B0C0D
的int類型變量為例杖剪,它的內(nèi)存為0x100~0x103,則:
內(nèi)存地址 | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
存儲(chǔ)單元 | 0x0A | 0X0B | 0X0C | 0X0D |
示例中驰贷,最高位字節(jié)是0x0A 存儲(chǔ)在最低的內(nèi)存地址處盛嘿。下一個(gè)字節(jié)0x0B存在后面的地址處。正類似于十六進(jìn)制字節(jié)從左到右的閱讀順序饱苟。
小端序
低位字節(jié)在前孩擂,高位字節(jié)在后,現(xiàn)大部分計(jì)算機(jī)內(nèi)部處理都是小端序箱熬。同樣以上面做例子:
內(nèi)存地址 | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
存儲(chǔ)單元 | 0x0D | 0X0C | 0X0B | 0X0A |
最低位字節(jié)是0x0D 存儲(chǔ)在最低的內(nèi)存地址處类垦。后面字節(jié)依次存在后面的地址處。
實(shí)際意義
到這里我們可以發(fā)現(xiàn)城须,在日常開發(fā)中蚤认,如果不熟悉字節(jié)序的情況下,在涉及字節(jié)的讀取和解析容易出現(xiàn)問題糕伐,那么砰琢,為什么要區(qū)分大端和小端呢,統(tǒng)一不是更方便嗎?
其實(shí)這里涉及一個(gè)效率的問題陪汽,計(jì)算機(jī)電路先處理低位字節(jié)训唱,效率比較高,因?yàn)橛?jì)算都是從低位開始的挚冤。如果都是大端序况增,則計(jì)算時(shí)需要從高位找到低位,再從低位計(jì)算到高位训挡,影響效率澳骤。所以,計(jì)算機(jī)的內(nèi)部處理都是小端字節(jié)序澜薄。但是我們?nèi)祟愡€是習(xí)慣讀寫大端字節(jié)序为肮。所以,除了計(jì)算機(jī)的內(nèi)部處理肤京,其他的場(chǎng)合幾乎都是大端字節(jié)序颊艳,比如網(wǎng)絡(luò)傳輸和文件儲(chǔ)存。
計(jì)算機(jī)處理字節(jié)序的時(shí)候蟆沫,不知道什么是高位字節(jié)籽暇,什么是低位字節(jié)。它只知道按順序讀取字節(jié)饭庞,先讀第一個(gè)字節(jié)戒悠,再讀第二個(gè)字節(jié)。如果是大端字節(jié)序舟山,先讀到的就是高位字節(jié)绸狐,后讀到的就是低位字節(jié)。小端字節(jié)序正好相反累盗。只有讀取的時(shí)候寒矿,才必須區(qū)分字節(jié)序,其他情況都不用考慮若债。
BOM
我們知道符相,UTF-16和UTF-32都是多字節(jié)的編碼規(guī)則,那在讀取的時(shí)候必然也會(huì)涉及到字節(jié)序的問題蠢琳,計(jì)算機(jī)是通過什么判斷編碼之后的字節(jié)序呢啊终,答案就是BOM。
字節(jié)順序標(biāo)記(byte-order mark傲须,BOM)是位于碼點(diǎn)U+FEFF
的統(tǒng)一碼字符的名稱蓝牲。當(dāng)以UTF-16或UTF-32來將UCS/統(tǒng)一碼字符所組成的字符串編碼時(shí),這個(gè)字符被用來標(biāo)示其字節(jié)序泰讽。它常被用來當(dāng)做標(biāo)示文件是以UTF-8例衍、UTF-16或UTF-32編碼的標(biāo)記昔期。而 FFFE 在 UCS 中是不存在的字符,所以不會(huì)出現(xiàn)在實(shí)際傳輸中佛玄。UCS 規(guī)范建議我們?cè)趥鬏斪止?jié)流前硼一,先傳輸BOM標(biāo)記。這樣如果接收者收到 FEFF翎嫡,就表明這個(gè)字節(jié)流是大端序的欠动;如果收到 FFFE,就表明這個(gè)字節(jié)流是小端序的惑申。
UTF-8 不需要 BOM 來表明字節(jié)順序,但可以用 BOM 來表明編碼方式翅雏。BOM的 UTF-8 編碼是 EF BB BF圈驼。所以如果接收者收到以 EF BB BF 開頭的字節(jié)流,就知道這是 UTF-8 編碼了望几。Windows 就是使用 BOM 來標(biāo)記文本文件的編碼方式的绩脆。微軟在 UTF-8 中使用 BOM 是因?yàn)檫@樣可以把 UTF-8 和 ASCII 等編碼明確區(qū)分開,但這樣的文件在 Windows 之外的操作系統(tǒng)里會(huì)帶來問題橄抹。
最后我們?cè)賮韺?duì)比一下攜帶BOM之后UTF-16編碼所得到的結(jié)果靴迫,其中UTF-16BE代表大端序,UTF-16LE代表小端序: