計算機只理解二進制,。這意味著 0 和 1 構成了計算機使用的語言。 一位是 0 或 1 ,。8 位組成一個字節(jié),。從這些簡單的部分,我們可以構建極其復雜的連接計算機系統(tǒng)來渲染視頻,、顯示來自世界各地的文本并計算極其復雜的算法,。 一些數(shù)據(jù)(一些英文字符,如 a,、e,、i、o 和 u)可以用一個字節(jié)表示,,但有些數(shù)據(jù)需要多個字節(jié)來表示,。 但是字節(jié)順序是計算機如何讀取和理解字節(jié)的基本部分。 字節(jié)序(英文:byte-order 或Endianness)是指計算機存儲和傳輸鏈路中,,多字節(jié)數(shù)據(jù)的字節(jié)排列順序,。 Endianness一詞來源于Jonathan Swift的小說《格列佛游記》,小說中兩派人因為吃煮雞蛋先打破小頭還是大頭爭論不休,。丹尼·科恩(Danny Cohen)在1980年發(fā)表的一篇互聯(lián)網(wǎng)實驗筆記中,,將大端和小端這兩個術語引入計算機科學,用于描述字節(jié)排列順序,。 多字節(jié)數(shù)據(jù)字節(jié)間排列方式規(guī)則如下: 大端序(Big-Endian)將數(shù)據(jù)的低位字節(jié)存放在內存的高位地址,,高位字節(jié)存放在低位地址。這種排列方式與數(shù)據(jù)用字節(jié)表示時的書寫順序一致,,符合人類的閱讀習慣,。除了計算機的內部處理,其他的場合幾乎都是大端字節(jié)序,,比如網(wǎng)絡傳輸和文件儲存,。 小端序(Little-Endian),將多字節(jié)數(shù)據(jù)的低位放在較小的地址處,,高位放在較大的地址處,,則稱小端序,。小端序與人類的閱讀習慣相反,但更符合計算機讀取內存的方式,,因為CPU讀取內存中的數(shù)據(jù)時,,是從低地址向高地址方向進行讀取的。 舉個具體的例子: 十六進制數(shù)0x12345678,如果按大端序存儲,,沿內存增長方向順序存放,。 如果按小端序存儲,將得到下圖結果,。 這里要注意,,小端序每個字節(jié)內部還是按大端序存儲的。也就是說,,0x12345678的小端序存儲為0x78563412,,而不是0x87654321 計算機內部字節(jié)序往往由CPU架構決定。許多歷史和現(xiàn)存的處理器采用大端內存表示,。有些混合使用兩種格式,,稱為中端、混合端或pdp-11端,。 lx86,,MOS Technology 6502,Z80,,VAX,,PDP-11等處理器為Little endian。 lMotorola 6800,,Motorola 68000,,PowerPC 970,System/370,,SPARC(除V9外)等處理器為Big endian,。 lARM, PowerPC (除PowerPC 970外), DEC Alpha, SPARC V9, MIPS, PA-RISC and IA64的字節(jié)序是可配置的。 為什么小端序不太好理解,,還一定要用呢,?據(jù)說是因為計算是從低位開始的,CPU采用小端序的方式處理數(shù)據(jù)效率更高,,因此一般計算機內部處理很多都選擇小端字節(jié)序,。 但是人類更容易理解大端序,網(wǎng)絡傳輸和文件儲存往往采用大端序,。其實一般用戶不用太關心字節(jié)序的問題,程序員則要關心計算機內部字節(jié)序和外部字節(jié)序之間的轉換問題,。 你有沒有注意過,,最樸實的文本編輯器在保存文件時候,,也可以選擇不同的編碼。 五種編碼相信大家都挺熟悉了,。我們在文本編輯器中寫入“讓我們測試一下吧”幾個漢字,,然后分別存為這五種編碼。然后用winhex打開,。 比較一下上圖UTF16-LE和UTF16-BE兩個文件,,文件頭分別是FFFE和FEFF。因為是UTF-16編碼,,每個漢字占兩個字節(jié),,存在字節(jié)序問題??瓷蠄D里面的字節(jié)位置,,UTF-16LE是小端序,UTF-16BE是大端序 還有一個奇怪編碼,,就是這個”帶有BOM的UTF-8”,。BOM(byte order mark)實際上就是字節(jié)序標記的意思。但是我們都知道UTF-8不存在字節(jié)序問題,,為什么還要加BOM呢,?BOM是為 UTF-16 和 UTF-32 準備的,用于標記字節(jié)序(byte order),。微軟在 UTF-8 中使用 BOM 是因為這樣可以把 UTF-8 和 ASCII 等編碼明確區(qū)分開,,但這樣的文件在 Windows 之外的操作系統(tǒng)里會帶來問題?!窾TF-8」和「帶 BOM 的 UTF-8」的區(qū)別就是有沒有 BOM,。即文件開頭有沒有FFBBEF。 大家如果仔細看會發(fā)現(xiàn),,同樣的數(shù)據(jù),,如果解析選擇的字節(jié)序和數(shù)據(jù)不匹配就會是亂碼,可見數(shù)據(jù)就在那里,,怎么解讀數(shù)據(jù)很重要,。 再看一個例子: 現(xiàn)代PC絕大多數(shù)采用小端字節(jié)序,我們一般成為主機字節(jié)序,。而TCP/IP協(xié)議在RFC1700中規(guī)定使用“大端”字節(jié)序為網(wǎng)絡字節(jié)序,,這與具體的CPU類型、操作系統(tǒng)等無關,,從而可以保證數(shù)據(jù)在不同主機之間傳輸時能夠被正確解釋,。 當多臺電腦進行通信時,如果雙方字節(jié)序不匹配,,會造成通信解析錯誤,。因此如果高于8位的數(shù)據(jù)要進行網(wǎng)絡傳輸,,需要先將數(shù)據(jù)轉換為大端再進行發(fā)送,對于接收到的數(shù)據(jù),,根據(jù)接收機器自身的存儲方式進行大小端轉換后再使用,。 BSD Socket提供了封裝好的轉換接口,包括四個函數(shù),,分別是htons(把unsigned short類型從主機序轉換到網(wǎng)絡序),、htonl (把unsigned long類型從主機序轉換到網(wǎng)絡序)、ntohs (把unsigned short類型從網(wǎng)絡序轉換到主機序)和ntohl (把unsigned long類型從網(wǎng)絡序轉換到主機序),。 這里我們看一個wireshark的抓到的ICMP協(xié)議報文,。其中Identifier(BE)、Identifier(LE),、Sequence number(BE),、Sequence number(LE)分別代表什么含義呢? Identifier(BE)指的是標示符(大端順序):1(0x0100),; Identifier(LE)指的是標示符(小端順序):256(0x0100),; Sequence number(BE)指的是序列號(大端順序):31(0x001f) Sequence number(LE)指的是序列號(小端順序):7936(0x1f00) 為什么要搞這么復雜呢?原因是wireshark考慮到window系統(tǒng)與Linux系統(tǒng)發(fā)出的ping報文(主要指ping應用字段而非包含IP頭的ping包)字節(jié)順序不同,,windows發(fā)出的報文是小端序LE,,Linux為大端序BE),所以wireshark這里給出了兩種字節(jié)序數(shù)據(jù)解析結果,,實際上原始數(shù)據(jù)都是一樣的,。 實驗:判斷主機字節(jié)序的方法 確定一個多字節(jié)的值(下面使用的是4字節(jié)的整數(shù)),將其寫入內存(即賦值給一個變量),,然后用指針取其首地址所對應的字節(jié)(即低地址的一個字節(jié)),,判斷該字節(jié)存放的是高位還是低位,高位說明是大端序,,低位說明是小端序,。 #include int main { unsigned int x = 0x12345678; char *c = (char*)&x; if (*c == 0x78) { printf("Little endian"); } else { printf("Big endian"); } return 0; } 什么是字節(jié)序? 計算機只理解二進制。這意味著 0 和 1 構成了計算機使用的語言,。 一位是 0 或 1 ,。8 位組成一個字節(jié)。從這些簡單的部分,,我們可以構建極其復雜的連接計算機系統(tǒng)來渲染視頻,、顯示來自世界各地的文本并計算極其復雜的算法。 一些數(shù)據(jù)(一些英文字符,,如 a,、e、i,、o 和 u)可以用一個字節(jié)表示,,但有些數(shù)據(jù)需要多個字節(jié)來表示,。 但是字節(jié)順序是計算機如何讀取和理解字節(jié)的基本部分。 什么是字節(jié)序,? 不同的語言以不同的順序閱讀他們的文本。例如,,英語從左到右閱讀,,而阿拉伯語從右到左閱讀。 這正是計算機的字節(jié)序,。 如果我的計算機從左到右讀取字節(jié),,而您的計算機從右到左讀取,那么當我們需要通信時就會出現(xiàn)問題,。 字節(jié)序意味著計算機內存中的字節(jié)按一定順序讀取,。 如果我們永遠不需要共享信息,我們就不會有任何問題,。每臺計算機對于它們自己的數(shù)據(jù)都是內部一致的,。只是互聯(lián)網(wǎng)使我們能夠共享比以往更多的數(shù)據(jù),而且我們的數(shù)據(jù)并不總是以相同的順序讀取,。 Endianness以兩種方式表示Big-endian ( BE ) 和Little-endian ( LE ),。 - BE先存儲大端。當讀取多個字節(jié)時,,第一個字節(jié)(或最低的內存地址)是最大的 - 所以對于從左到右閱讀的人來說最有意義,。 - LE首先存儲小端。當讀取多個字節(jié)時,,第一個字節(jié)(或最低的內存地址)是最小的 - 所以對于從右到左閱讀的人來說最有意義,。 如果上述內容沒有意義,那沒關系,,讓我們看一個例子,。 字節(jié)順序如何工作的示例 讓我們取一個我們必須使用多個字節(jié)來表示的數(shù)字,并展示 它可以表示的大端和小端方式,。 我們將采用一個需要三個字節(jié)才能以二進制表示的數(shù)字,。 這可能稍微簡化了它,但我希望它可以作為一個有用的視覺解釋,。 一個二進制示例,,其中 big-endian 和 little-endian 數(shù)字按讀取順序排列。 開頭的 0b 只是為了讓讀者知道它是二進制的,。所以我們知道二進制 1100 和十進制數(shù) 1,100 之間的區(qū)別(一千,,一百)。我還使用了顏色希望使它更清晰,。 我只是想明確一點,,位排序很好,。位的順序沒有區(qū)別。但是字節(jié)的正確順序是有區(qū)別的,。我希望以上演示了一個字節(jié)內 0 和 1 的順序不要改變,。但是字節(jié)順序確實發(fā)生了變化。 如果我們也只需要發(fā)送一個字節(jié),,就沒有問題(沒有多種方法可以只訂購一件東西),。這只是一個多于一個字節(jié)的序列的問題。 最高有效字節(jié) (MSbyte) 術語最高有效字節(jié)是描述字節(jié)順序的常用方法,,因此我想確保徹底涵蓋它,。 在我們開始解釋bits和bytes之前, 讓我們用十進制數(shù)來做,。 如果我取十進制數(shù) 2,984,,你可以改變什么數(shù)字來改變最小的數(shù)量?答案是個位數(shù) 4. 如果我把 4 改成 5,,整數(shù)只會增加 1,。 但是,假設您將最高位 2 更改在 2,984 中,。它將顯著改變數(shù)字并增加一千,。 這與bytes和bits完全相同。 我們將保持最小位置的字節(jié)稱為最低有效字節(jié)( LSbyte ),,將保持最小位置的位稱為最低有效位( LSbit ),。 一個圖表來說明包含最低位置編號的字節(jié)是最低有效字節(jié)。 保存最高有效位的字節(jié)稱為最高有效字節(jié)( MSbyte ),,保存最高有效位位置的位稱為最高有效位( MSbit ),。 現(xiàn)在知道了這個新定義,我們可以將BE和LE定義為:
這什么時候會成為問題,? 在一些不同的情況下,,字節(jié)序必須是計算中的一個考慮因素。 例如,,Unicode 字符(用于在您的手機,、PC、電視等任何地方呈現(xiàn)字符的字符集?。┍仨殏鬟f一個特殊的字符字節(jié)序列 (U+FEFF BYTE ORDER MARK),,稱為Byte Order Mark或BOM。BOM有幾個用途,。 BOM使系統(tǒng)知道:
一些編程語言甚至希望您詳細說明正在使用的字節(jié)順序,。因此,,一個程序可以根據(jù)您的需要使用、發(fā)送和接收BE或LE中的數(shù)字,。 為什么這首先是一個問題 ,? 碰巧出現(xiàn)了不同的協(xié)議,然后不得不相互交互,。BE是任何網(wǎng)絡協(xié)議中的主導順序,,例如稱為網(wǎng)絡順序。另一方面,,大多數(shù) PC 都是little-endian的。 您可以在此處在線運行 [C++](http:///524wi) 代碼片段,,以查看您的機器是什么字節(jié)序(我的是little-endian),。 字節(jié)序在很大程度上不再對高級語言產(chǎn)生影響,并且抽象出我們不需要擔心的特定實現(xiàn)細節(jié),。 它的另一部分是處理器決定它們是小端還是大端(或者可以同時處理兩者 - 稱為Bi-endia 字節(jié)序(Endianness)簡介 字節(jié)序(Endianness)指的是多字節(jié)數(shù)據(jù)的內存排列順序,。 字節(jié)的排列方式有兩個: 大端序(Big-Endian)將數(shù)據(jù)的低位字節(jié)存放在內存的高位地址,高位字節(jié)存放在低位地址,。 小端序(Little-Endian)將數(shù)據(jù)的的低位字節(jié)放在較小的地址處,,高位字節(jié)放在較大的地址處。 比如數(shù)字 0x1A 34 5C 78在內存中的表示形式為: 1)大端模式: 低地址 -----------------> 高地址 0x1A | 0x34 | 0x5C | 0x78 2)小端模式: 低地址 ------------------> 高地址 0x78 | 0x5C | 0x34 | 0x1A 為什么會有大小端模式之分呢,? 這是因為在計算機中,,我們是以字節(jié)為單位的,每個地址單元都對應著一個字節(jié),,一個字節(jié)為 8 bit,,對于多字節(jié)的數(shù)據(jù),如C語言的int(32位機中一般占4字節(jié)),,那么必然存在著一個如果將多個字節(jié)安排的問題,。因此就導致了大端存儲模式和小端存儲模式。 字節(jié)順序使用情況: 以1字節(jié)為基本單位的文件格式獨立于字節(jié)順序,,例如ASCII文件,。 其他文件格式使用一些固定的端順序格式,例如JPEG文件以大端順序格式存儲,。 java 全部為大端(與平臺無關): Java二進制文件中的所有內容都以大端順序存儲,。這意味著如果您只使用Java,那么所有文件在所有平臺(Mac,、PC,、UNIX等)上的處理方式都是相同的。 n),因此消費者選擇驅動了我們認為計算機系統(tǒng)中“正?!钡牟糠謨热?。 |
|