小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

理解Big和Little Endian字節(jié)順序

 BIGDATA云 2018-08-06
字節(jié)順序的問題令人沮喪,我想讓你免除我經(jīng)歷的悲痛。這是關(guān)鍵:

問題:計(jì)算機(jī)使用不同的語言,就像人一樣。 有些人將數(shù)據(jù)“從左到右”,其他人從“從右到左”。
機(jī)器可以很好地讀取自己的數(shù)據(jù) - 當(dāng)一臺(tái)計(jì)算機(jī)存儲(chǔ)數(shù)據(jù)而另一種類型嘗試讀取數(shù)據(jù)時(shí)會(huì)出現(xiàn)問題。
解決方案
同意通用格式(即,所有網(wǎng)絡(luò)流量遵循單一格式),或
始終包含描述數(shù)據(jù)格式的標(biāo)頭。如果標(biāo)題向后顯示,則表示數(shù)據(jù)以其他格式存儲(chǔ),需要轉(zhuǎn)換。
數(shù)字與數(shù)據(jù)
最重要的概念是識(shí)別數(shù)字與表示數(shù)字的數(shù)據(jù)之間的差異。

一個(gè)數(shù)是一個(gè)抽象的概念,如東西計(jì)數(shù)。你有十個(gè)手指。無論您使用什么樣的表示,“十”的概念都不會(huì)改變:十,十,迪茲(西班牙語),ju(日語),1010(二進(jìn)制),X(羅馬數(shù)字)......這些表示都指向同樣的“十”概念。

將其與數(shù)據(jù)進(jìn)行對(duì)比。數(shù)據(jù)是物理概念,是存儲(chǔ)在計(jì)算機(jī)上的原始比特和字節(jié)序列。數(shù)據(jù)沒有固有的含義,必須由閱讀它的人解釋。

數(shù)據(jù)就像人類寫作,這只是紙上的標(biāo)記。這些標(biāo)記沒有固有的含義。如果我們看到一條線和一條圓(如:| O),我們可能會(huì)將其解釋為“十”。

但是我們假設(shè)標(biāo)記是指一個(gè)數(shù)字。它們可能是木星的“IO”字母?;蛘咭苍S是希臘女神。或者也許是輸入/輸出的縮寫?;蚰橙说拿挚s寫?;蚨M(jìn)制數(shù)字2(“10”)??赡苄粤斜砝^續(xù)。

關(guān)鍵是單個(gè)數(shù)據(jù)(| O)可以用多種方式解釋,并且在有人澄清作者的意圖之前,其含義尚不清楚。

計(jì)算機(jī)面臨同樣的問題。它們存儲(chǔ)數(shù)據(jù),而不是抽象概念,并使用1和0的序列來存儲(chǔ)數(shù)據(jù)。之后,他們回讀了1和0,并嘗試從原始數(shù)據(jù)中重新創(chuàng)建抽象概念。根據(jù)所做的假設(shè),1和0可能意味著非常不同的東西。

為什么會(huì)出現(xiàn)這個(gè)問題?嗯,沒有規(guī)則所有計(jì)算機(jī)必須使用相同的語言,就像所有人都不需要的規(guī)則一樣。每種類型的計(jì)算機(jī)都是內(nèi)部一致的(它可以讀回自己的數(shù)據(jù)),但不能保證其他類型的計(jì)算機(jī)如何解釋它創(chuàng)建的數(shù)據(jù)。

基本概念

數(shù)據(jù)(位和字節(jié),或紙上的標(biāo)記)毫無意義; 它必須被解釋為創(chuàng)建一個(gè)抽象概念,如數(shù)字。
與人類一樣,計(jì)算機(jī)有不同的方式來存儲(chǔ)相同的抽象概念。(也就是說,我們有很多方法可以說“十”:十,十,二等)
將數(shù)字存儲(chǔ)為數(shù)據(jù)
值得慶幸的是,大多數(shù)計(jì)算機(jī)都同意一些基本的數(shù)據(jù)格式(情況并非總是這樣)。這為我們提供了一個(gè)共同的起點(diǎn),使我們的生活更輕松:

有兩個(gè)值(開或關(guān),1或0)
一個(gè)字節(jié)是一個(gè)8位的序列
字節(jié)中“最左邊”的位是最大的。因此,二進(jìn)制序列00001001是十進(jìn)制數(shù)9. 00001001 =(2 3 + 2 0 = 8 + 1 = 9)。
位從右到左編號(hào)。位0是最右邊和最小的; 第7位是最左邊和最大的。
我們可以將這些基本協(xié)議用作交換數(shù)據(jù)的構(gòu)建塊。如果我們一次存儲(chǔ)和讀取一個(gè)字節(jié)的數(shù)據(jù),它將適用于任何計(jì)算機(jī)。字節(jié)的概念在所有機(jī)器上都是相同的,并且在所有機(jī)器上,哪個(gè)字節(jié)是第一個(gè),第二個(gè),第三個(gè)(字節(jié)0,字節(jié)1,字節(jié)2 ......)的想法是相同的。

如果計(jì)算機(jī)同意每個(gè)字節(jié)的順序,那么問題是什么?

嗯,這適用于單字節(jié)數(shù)據(jù),如ASCII文本。但是,需要使用多個(gè)字節(jié)存儲(chǔ)大量數(shù)據(jù),如整數(shù)或浮點(diǎn)數(shù)。并且沒有就如何存儲(chǔ)這些序列達(dá)成一致。

字節(jié)示例
考慮一個(gè)4字節(jié)的序列,名為WXY和Z - 我避免將它們命名為ABCD,因?yàn)樗鼈兪鞘M(jìn)制數(shù)字,這會(huì)令人困惑。因此,每個(gè)字節(jié)都有一個(gè)值,由8位組成。

 字節(jié)名稱:WXYZ
 地點(diǎn):0 1 2 3
 值(十六進(jìn)制):0x12 0x34 0x56 0x78
例如,W是整個(gè)字節(jié),十六進(jìn)制為0x12或二進(jìn)制為00010010。如果W被解釋為一個(gè)數(shù)字,它將是十進(jìn)制的“18”(順便說一下,沒有什么可以說我們必須把它解釋為一個(gè)數(shù)字 - 它可能是一個(gè)ASCII字符或完全不同的東西)。

和我一起到目前為止?我們有4個(gè)字節(jié),WXY和Z,每個(gè)字節(jié)都有不同的值。

理解指針
指針是編程的關(guān)鍵部分,尤其是C編程語言。指針是引用內(nèi)存位置的數(shù)字。由我們(程序員)來解釋該位置的數(shù)據(jù)。

在C中,當(dāng)您將指針強(qiáng)制轉(zhuǎn)換為某種類型(例如char *或int *)時(shí),它會(huì)告訴計(jì)算機(jī)如何解釋該位置的數(shù)據(jù)。例如,讓我們聲明

void * p = 0; // p是指向未知數(shù)據(jù)類型的指針
             // p是一個(gè)NULL指針 - 不要取消引用
char * c; // c是指向char的指針,通常是單個(gè)字節(jié)
請(qǐng)注意,我們無法從p獲取數(shù)據(jù),因?yàn)槲覀儾恢浪念愋?。p可以指向一個(gè)數(shù)字,一個(gè)字母,一個(gè)字符串的開頭,你的星座,一個(gè)圖像 - 我們只是不知道要讀取多少字節(jié),或者如何解釋那里有什么。

現(xiàn)在,假設(shè)我們寫

c =(char *)p;
啊 - 現(xiàn)在這個(gè)語句告訴計(jì)算機(jī)指向與p相同的位置,并將數(shù)據(jù)解釋為單個(gè)字符(char通常是單個(gè)字節(jié),uint8_t如果在您的機(jī)器上使用,則使用)。在這種情況下,c將指向存儲(chǔ)器位置0或字節(jié)W.如果我們打印c,我們將得到W中的值,即十六進(jìn)制0x12(記住W是整個(gè)字節(jié))。

這個(gè)例子不依賴于我們擁有的計(jì)算機(jī)類型 - 同樣,所有計(jì)算機(jī)都同意單個(gè)字節(jié)是什么(過去不是這種情況)。

這個(gè)例子很有用,即使它在所有計(jì)算機(jī)上都是一樣的 - 如果我們有一個(gè)指向單個(gè)字節(jié)的指針(char *,一個(gè)字節(jié)),我們可以遍歷內(nèi)存,一次讀取一個(gè)字節(jié)。我們可以檢查任何內(nèi)存位置和計(jì)算機(jī)的字節(jié)順序無關(guān)緊要 - 每臺(tái)計(jì)算機(jī)都會(huì)返回相同的信息。

所以有什么問題?
計(jì)算機(jī)嘗試讀取多個(gè)字節(jié)時(shí)出現(xiàn)問題。某些數(shù)據(jù)類型包含多個(gè)字節(jié),如長整數(shù)或浮點(diǎn)數(shù)。單個(gè)字節(jié)只有256個(gè)值,因此可以存儲(chǔ)0 - 255。

現(xiàn)在出現(xiàn)問題 - 當(dāng)您讀取多字節(jié)數(shù)據(jù)時(shí),最大字節(jié)出現(xiàn)在哪里?

大端機(jī):用于存儲(chǔ)數(shù)據(jù)的第一大終端。查看多個(gè)字節(jié)時(shí),第一個(gè)字節(jié)(最低地址)是最大的。
小端機(jī):首先存儲(chǔ)數(shù)據(jù)小端。查看多個(gè)字節(jié)時(shí),第一個(gè)字節(jié)最小。
命名是有道理的,是嗎?Big-endian認(rèn)為大端是第一位的。(順便說一句,big-endian / little-endian命名來自Gulliver's Travels,Lilliputans爭論是否要在小端或大端打破雞蛋。有時(shí)計(jì)算機(jī)辯論同樣有意義:-))

同樣,如果您有一個(gè)字節(jié),則endian-ness無關(guān)緊要。如果你有一個(gè)字節(jié),它是你讀取的唯一數(shù)據(jù),所以只有一種方法可以解釋它(同樣,因?yàn)橛?jì)算機(jī)同意一個(gè)字節(jié)是什么)。

現(xiàn)在假設(shè)我們將4個(gè)字節(jié)(WXYZ)以相同的方式存儲(chǔ)在大端和小端機(jī)器上。也就是說,兩臺(tái)機(jī)器上的內(nèi)存位置0都是W,內(nèi)存位置1是X等。

我們可以通過記住字節(jié)與機(jī)器無關(guān)來創(chuàng)建這種安排。我們可以一次走一段內(nèi)存,然后設(shè)置我們需要的值。這適用于任何機(jī)器:

c = 0; //指向位置0(不適用于真機(jī)!)
* c = 0x12; //設(shè)置W的值
c = 1; //指向位置1
* c = 0x34; //設(shè)置X的值
... //重復(fù)Y和Z; 細(xì)節(jié)留給讀者
此代碼適用于任何機(jī)器,我們?cè)谖恢?,1,2和3中都設(shè)置了字節(jié)W,X,Y和Z.

解釋數(shù)據(jù)
現(xiàn)在讓我們用多字節(jié)數(shù)據(jù)做一個(gè)例子(最后!)??焖倩仡櫍骸岸陶麛?shù)”是一個(gè)2字節(jié)(16位)的數(shù)字,范圍從0到65535(如果是無符號(hào))。我們?cè)谝粋€(gè)例子中使用它:

短* s; //指向short int的指針(2個(gè)字節(jié))
s = 0; //指向位置0; * s是值
因此,s是指向short的指針,現(xiàn)在正在查看字節(jié)位置0(具有W)。當(dāng)我們讀取s的值時(shí)會(huì)發(fā)生什么?

Big endian機(jī)器:我認(rèn)為short是兩個(gè)字節(jié),所以我將把它們讀掉:位置s是地址0(W或0x12),位置s + 1是地址1(X或0x34)。由于第一個(gè)字節(jié)最大(我是大端!),數(shù)字必須是256 *字節(jié)0 +字節(jié)1,或256 * W + X或0x1234。我將第一個(gè)字節(jié)乘以256(2 ^ 8)因?yàn)槲倚枰獙⑺莆?位。

小端機(jī):我不知道Big Endian先生在吸煙。是的,我同意短路是2個(gè)字節(jié),我會(huì)像他一樣讀取它們:位置s是0x12,位置s + 1是0x34。但在我的世界里,第一個(gè)字節(jié)是最小的!short的值是字節(jié)0 + 256 *字節(jié)1,或256 * X + W或0x3412。

請(qǐng)記住,兩臺(tái)機(jī)器都從位置開始,讀取內(nèi)存向上。關(guān)于位置0和位置1的含義沒有混淆。短路是2個(gè)字節(jié)沒有混淆。

但是你看到了這個(gè)問題嗎?big-endian機(jī)器認(rèn)為s = 0x1234并且little-endian機(jī)器認(rèn)為s = 0x3412。相同的確切數(shù)據(jù)給出了兩個(gè)不同的數(shù)字??赡懿皇且患檬?。

又一個(gè)例子
讓我們用另一個(gè)4字節(jié)整數(shù)的例子來表示“有趣”:

int * i; //指向int的指針(32位機(jī)器上的4個(gè)字節(jié))
i = 0; //指向位置零,所以* i是那里的值
我們?cè)俅螁枺何业膬r(jià)值是什么?

大端機(jī)器:int是4個(gè)字節(jié),第一個(gè)是最大的。我讀了4個(gè)字節(jié)(WXYZ),W是最大的。號(hào)碼是0x12345678。
小端機(jī)器:當(dāng)然,int是4個(gè)字節(jié),但第一個(gè)是最小的。我也讀過WXYZ,但W屬于后面 - 這是最小的。號(hào)碼是0x78563412。
相同的數(shù)據(jù),不同的結(jié)果 - 不是一件好事。這是一個(gè)使用上面數(shù)字的交互式示例,隨意插入您自己的:


NUXI問題
字節(jié)順序的問題有時(shí)被稱為NUXI問題:存儲(chǔ)在big-endian機(jī)器上的UNIX可以在小端機(jī)器上顯示為NUXI。

假設(shè)我們要將4個(gè)字節(jié)(U,N,I和X)存儲(chǔ)為兩個(gè)短路:UN和IX。每個(gè)字母都是整個(gè)字節(jié),就像我們上面的WXYZ例子一樣。要存儲(chǔ)這兩條短褲我們會(huì)寫:

短* s; //設(shè)置短褲的指針
s = 0; //指向位置0
* s =聯(lián)合國; //存儲(chǔ)第一個(gè)短:U * 256 + N(虛構(gòu)代碼)
s = 2; //指向下一個(gè)位置
* s = IX; //存儲(chǔ)第二個(gè)短片:I * 256 + X.
此代碼不是特定于計(jì)算機(jī)的。如果我們將“UN”存儲(chǔ)在一臺(tái)機(jī)器上并要求將其讀回來,最好是“UN”!我不關(guān)心端序問題,如果我們?cè)谝慌_(tái)機(jī)器上存儲(chǔ)一個(gè)值并在同一臺(tái)機(jī)器上讀回它,它必須是相同的值。

但是,如果我們一次查看一個(gè)字節(jié)的內(nèi)存(使用我們的char *技巧),順序可能會(huì)有所不同。在大端機(jī)器上,我們看到:

字節(jié):UNIX
地點(diǎn):0 1 2 3
哪個(gè)有意義。U是“UN”中的最大字節(jié),首先存儲(chǔ)。對(duì)于IX來說也是如此:我是最大的,并且首先存儲(chǔ)。

在小端機(jī)器上我們會(huì)看到:

字節(jié):NUXI
地點(diǎn):0 1 2 3
這也是有道理的?!癗”是“UN”中最小的字節(jié),首先存儲(chǔ)。同樣,即使字節(jié)在存儲(chǔ)器中“向后”存儲(chǔ),小端機(jī)器也知道它是小端,并在讀取值時(shí)正確解釋它們。另外,請(qǐng)注意我們可以在任何機(jī)器上指定十六進(jìn)制數(shù)字,例如x = 0x1234。即使是一個(gè)小端機(jī)器也知道你寫0x1234時(shí)的意思,并且不會(huì)強(qiáng)迫你自己交換這些值(你指定要寫入的十六進(jìn)制數(shù),它會(huì)計(jì)算出細(xì)節(jié)并交換內(nèi)存中的字節(jié),在覆蓋。棘手。)。

這種情況稱為“NUXI”問題,因?yàn)樽止?jié)序列UNIX在另一種類型的機(jī)器上被解釋為NUXI。同樣,如果您交換數(shù)據(jù),這只是一個(gè)問題 - 每臺(tái)機(jī)器都是內(nèi)部一致的。

在Endian機(jī)器之間交換數(shù)據(jù)
計(jì)算機(jī)是連接在一起的 - 機(jī)器只需要擔(dān)心閱讀自己的數(shù)據(jù)的日子就消失了。大端和小端機(jī)器需要交談和相處。他們?nèi)绾巫龅竭@一點(diǎn)?

解決方案1:使用通用格式
最簡單的方法是同意通過網(wǎng)絡(luò)發(fā)送數(shù)據(jù)的通用格式。標(biāo)準(zhǔn)的網(wǎng)絡(luò)秩序?qū)嶋H上是大端的,但是有些人認(rèn)為小端沒有獲勝...我們只是稱之為“網(wǎng)絡(luò)秩序”。

要將數(shù)據(jù)轉(zhuǎn)換為網(wǎng)絡(luò)順序,計(jì)算機(jī)將調(diào)用函數(shù)hton(主機(jī)到網(wǎng)絡(luò))。在大端機(jī)器上,這實(shí)際上不會(huì)做任何事情,但我們不會(huì)在這里討論(小端可能會(huì)生氣)。

但是在發(fā)送數(shù)據(jù)之前使用hton很重要,即使你是big-endian也是如此。你的程序可能很受歡迎,它在不同的機(jī)器上編譯,你希望你的代碼是可移植的(不是嗎?)。

類似地,有一個(gè)用于從網(wǎng)絡(luò)讀取數(shù)據(jù)的功能ntoh(網(wǎng)絡(luò)到主機(jī))。您需要這樣做以確保正確地將網(wǎng)絡(luò)數(shù)據(jù)解釋為主機(jī)的格式。您需要知道正在接收的數(shù)據(jù)類型才能正確解碼,轉(zhuǎn)換功能如下:

 htons() - “主機(jī)到網(wǎng)絡(luò)短”
 htonl() - “主機(jī)到網(wǎng)絡(luò)長”
 ntohs() - “網(wǎng)絡(luò)主機(jī)短”
 ntohl() - “網(wǎng)絡(luò)主機(jī)長”
請(qǐng)記住,單個(gè)字節(jié)是單個(gè)字節(jié),順序無關(guān)緊要。

執(zhí)行低級(jí)網(wǎng)絡(luò)時(shí),這些功能至關(guān)重要,例如驗(yàn)證IP數(shù)據(jù)包中的校驗(yàn)和。如果你不能正確理解端序問題,你的生活將會(huì)很痛苦 - 請(qǐng)接受我的話。使用翻譯功能,并了解他們需要的原因。

解決方案2:使用字節(jié)訂單標(biāo)記(BOM)
另一種方法是在每個(gè)數(shù)據(jù)之前包括一個(gè)幻數(shù),例如0xFEFF。如果您讀取幻數(shù)并且它是0xFEFF,則表示數(shù)據(jù)與您的機(jī)器格式相同,一切都很好。

如果您讀取幻數(shù)并且它是0xFFFE(它是向后),則表示數(shù)據(jù)是以不同于您自己的格式寫入的。你必須翻譯它。

有幾點(diǎn)需要注意。首先,這個(gè)數(shù)字并不是真正的魔術(shù),但程序員經(jīng)常使用這個(gè)術(shù)語來描述任意數(shù)字的選擇(BOM可能是任何不同字節(jié)的序列)。它被稱為字節(jié)順序標(biāo)記,因?yàn)樗硎敬鎯?chǔ)數(shù)據(jù)的字節(jié)順序。

其次,BOM會(huì)增加所有傳輸數(shù)據(jù)的開銷。即使您只發(fā)送2個(gè)字節(jié)的數(shù)據(jù),也需要包含2個(gè)字節(jié)的BOM。哎喲!

Unicode 在存儲(chǔ)多字節(jié)數(shù)據(jù)時(shí)使用BOM(某些Unicode字符編碼每個(gè)字符可以有2個(gè),3個(gè)甚至4個(gè)字節(jié))。XML通過默認(rèn)情況下以UTF -8 存儲(chǔ)數(shù)據(jù)來避免這種混亂,它一次存儲(chǔ)一個(gè)字節(jié)的Unicode信息。為什么這很酷?

(第56次重復(fù))“因?yàn)樽止?jié)序問題對(duì)單個(gè)字節(jié)無關(guān)緊要”。

你是對(duì)的。

同樣,BOM也會(huì)出現(xiàn)其他問題。如果您忘記包含BOM,該怎么辦?您是否認(rèn)為數(shù)據(jù)的格式與您自己的格式相同?您是否閱讀了數(shù)據(jù)并查看它是否“向后”(無論這意味著什么)并嘗試翻譯它?如果常規(guī)數(shù)據(jù)巧合地包含BOM會(huì)怎么樣?這些情況并不好玩。

為什么會(huì)出現(xiàn)Endian問題?我們不能相處嗎?
啊,這是一個(gè)多么哲學(xué)的問題。

每個(gè)字節(jié)順序系統(tǒng)都有其優(yōu)點(diǎn)。Little-endian機(jī)器允許您首先讀取最低字節(jié),而不讀取其他字節(jié)。你可以很容易地檢查一個(gè)數(shù)字是奇數(shù)還是偶數(shù)(最后一位是0),如果你是這樣的話,這很酷。Big-endian系統(tǒng)將數(shù)據(jù)存儲(chǔ)在內(nèi)存中的方式與我們?nèi)祟悓?duì)數(shù)據(jù)的思考方式(從左到右)相同,這使得低級(jí)調(diào)試更容易。

但為什么不是每個(gè)人都同意一個(gè)系統(tǒng)呢?為什么某些計(jì)算機(jī)必須嘗試與眾不同?

讓我回答一個(gè)問題:為什么不是每個(gè)人都說同一種語言?為什么有些語言從左到右書寫,有些語言從右到左書寫?

有時(shí)通信系統(tǒng)是獨(dú)立開發(fā)的,后來需要進(jìn)行交互。

結(jié)語:分手思考
Endian問題是一般編碼問題的一個(gè)例子 - 數(shù)據(jù)需要表示抽象概念,后來需要從數(shù)據(jù)創(chuàng)建概念。這個(gè)主題值得擁有自己的文章(或系列),但你應(yīng)該更好地理解endian問題。更多信息:

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多