日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

彻底弄懂计算机中的大端小端

發(fā)布時(shí)間:2025/3/15 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 彻底弄懂计算机中的大端小端 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

大端與小端這個(gè)問題在做和其他設(shè)備交換原始字節(jié)數(shù)據(jù)的時(shí)候是非常重要的概念,也是必須要掌握的內(nèi)容,但是很多人就是僅僅是稍微有些了解,但每次真正去做東西的時(shí)候,還是要花半天去想,博主就是這樣的人,出現(xiàn)這樣問題的真正原因是還沒有完全弄清楚大端小端。今天就讓我們一起徹底的弄懂這兩個(gè)東西吧!

先講講關(guān)于這兩個(gè)東西的傳說(shuō)吧(也是抄來(lái)的^_^)

“大端”和“小端”可以追溯到1726年的Jonathan Swift的《格列佛游記》,其中一篇講到有兩個(gè)國(guó)家因?yàn)槌噪u蛋究竟是先打破較大的一端還是先打破較小的一端而爭(zhēng)執(zhí)不休,甚至爆發(fā)了戰(zhàn)爭(zhēng)。1981年10月,Danny Cohen的文章《論圣戰(zhàn)以及對(duì)和平的祈禱》(On holy wars and a plea for peace)將這一對(duì)詞語(yǔ)引入了計(jì)算機(jī)界。這么看來(lái),所謂大端和小端,也就是big-endian和little-endian,其實(shí)是從描述雞蛋的部位而引申到計(jì)算機(jī)地址的描述,也可以說(shuō),是從一個(gè)俚語(yǔ)衍化來(lái)的計(jì)算機(jī)術(shù)語(yǔ)。稍有些英語(yǔ)常識(shí)的人都會(huì)知道,如果單靠字面意思來(lái)理解俚語(yǔ),那是很難猜到它的正確含義的。在計(jì)算機(jī)里,對(duì)于地址的描述,很少用“大”和“小”來(lái)形容;對(duì)應(yīng)地,用的更多的是“高”和“低”;很不幸地,這對(duì)術(shù)語(yǔ)直接按字面翻譯過(guò)來(lái)就成了“大端”和“小端”,讓人產(chǎn)生迷惑也不是很奇怪的事了。

我希望這篇文章的讀者起碼要知道大端小端是干什么的,不然看了效果也不會(huì)很好

一個(gè)句話解釋什么是大端,什么是小端

在用英文屬于解釋就是,most significant (最高有效位)在低地址位就是大端,(least significat) 在高地址位就是小端,看完這句話,你是不是清楚了什么是大端,什么是小端了呢? 正常人的反應(yīng)會(huì)是,哎呀,我操,這都是些啥啊?不但沒有更清楚,反而更暈了,我開始看到這樣的解釋也是這樣的反應(yīng)。

再來(lái)一個(gè)問題,徹底搞暈?zāi)?#xff08;放心,我會(huì)把你搞清醒的^__^)

示例用C來(lái)描述

例1 :short num1 = 0x12FF; 例2 :char * str1 = "abcde"; 例3 :數(shù)字32的 short 十六進(jìn)制: 00 20

請(qǐng)問上面的代碼中 例1 是大端還是小端 , 例2 是大端還是小端,例3 是大端還是小端 ,我希望到這里我已經(jīng)成功的將你?搞暈?了。

根本原則,大端小端是針對(duì)于存儲(chǔ)而言的,和字面的表達(dá)方式?jīng)]關(guān)系

? ? 所以之前我提的問題全是些偽命題,而計(jì)算機(jī)中大端小端真正的含義要在存儲(chǔ)中講才能講明白。
????我們先來(lái)看例1 ,我們都知道在C中short 占用兩個(gè)字節(jié),我們這里給這兩個(gè)字節(jié)賦值為0x12 和0xFF,在計(jì)算機(jī)中內(nèi)存是一個(gè)個(gè)的字節(jié)單元。

????好了問題又來(lái)了,這兩個(gè)字節(jié)在內(nèi)存中是如果放的呢,假如 num1的 起始地址是 0x0056A100, 那么存放num1內(nèi)容的應(yīng)該是 0x0056A100和0x0056A101,但是哪個(gè)是0x12 ,哪個(gè)是0xFF呢? 我們寫一段代碼來(lái)看一下

int main(int argc, _TCHAR* argv[]){unsigned short num1 = 0x12FF;char * address = (char *)&num1;printf("low bytes is %x , high bytes is %x",*address & 0xFF, *(address + 1) & 0xFF ); }

程序很簡(jiǎn)單,就是分別打印兩個(gè)字節(jié)的內(nèi)容,低字節(jié)是address,高字節(jié)是address+1 , 我們來(lái)看一下 運(yùn)行結(jié)果

可以看到低位地址是0xFF高位是0x12,num1 這個(gè)數(shù)的高位12 存在了內(nèi)存的低地址處,低位FF存在高地址處, 所以我們的機(jī)器 是小端的機(jī)器,其實(shí)只要確定內(nèi)存的低地址存放的是高位還是低位就行了,這里低地址是0xFF(低位),所以是小端。代表我們的機(jī)器是小端機(jī)器,嚴(yán)格的說(shuō)是CPU處理數(shù)據(jù)的方式采用的是小端法。

字符串中又是怎樣的情況呢?

char * a = “abcd”;

其實(shí)在程序中字符串并沒有大端小端并之說(shuō),只有在涉及到數(shù)據(jù)的傳輸時(shí),字符串的大端小端才值的注意,我們后面會(huì)探討這一問題,但很多教材或者是博客都直接把整型和字符串的大小端放在一起講,就容易更讓人搞不清楚。這里的d肯定是存放在高地址,a肯定是存放在低地址。

大端小端和字符串沒有任何關(guān)系

網(wǎng)絡(luò)中的大端與小端

可能上面的內(nèi)容你已經(jīng)搞清楚了,但是當(dāng)你看一些關(guān)于網(wǎng)絡(luò)或者的資料時(shí)發(fā)現(xiàn)又有什么網(wǎng)絡(luò)字節(jié)序神馬的,然后又糊涂了,讓我們一起來(lái)破除關(guān)于網(wǎng)絡(luò)字節(jié)序列這些神馬的浮云。

-了解網(wǎng)絡(luò)是怎樣發(fā)送數(shù)據(jù)的?

我們使用的網(wǎng)絡(luò)協(xié)議很多都是基于socket的,所以我們基于socket來(lái)講,在socket規(guī)范中發(fā)送數(shù)據(jù)是 這個(gè)方法

send(Socket soc, char * buf, len , 0);
第一個(gè)參數(shù)是對(duì)方的socket,也就是地址
第二個(gè)參數(shù)是 一個(gè)字符指針,也就是要發(fā)送的內(nèi)容存放的地址
第三個(gè)是發(fā)送數(shù)據(jù)的長(zhǎng)度
第四個(gè)是和選擇協(xié)議相關(guān)的,一般設(shè)為0

所以這里我們看到在底層發(fā)送數(shù)據(jù)的方法里面根本沒有和什么大端小端有關(guān)系的東西,發(fā)送的函數(shù)只關(guān)心你要老子發(fā)送的東西在哪兒,發(fā)多少,其他一概不管,好,現(xiàn)在用一個(gè)場(chǎng)景說(shuō)明一下。程序員A把一個(gè)金額發(fā)給程序員B,這個(gè)金額是B欠A錢的金額。

//A發(fā)給B,這是B欠我A的數(shù)目 ,是1500元,下面是十六進(jìn)制寫法 short a = 0x05DC; //于是A就 send(sock, (char *)&a,2,0);

接收和發(fā)送的函數(shù)方法參數(shù)是一樣的
recv(Socket soc, char * buf, len , 0);
好,這個(gè)數(shù)目發(fā)完了,B接收的時(shí)候用下面的代碼

char ownMoney [2]; recv(Socket soc,ownMoney, 2 , 0);

好了,數(shù)據(jù)發(fā)送和接受都完成了,到這里為止,和大小端半毛錢關(guān)系都沒有,接下來(lái)就有了。這B想看看到底欠了A多少錢了,用下面的代碼接收。

int total = ((ownMoney[0] << 8) | (ownMoney[1] & 0xFF ) &0xFF );

一看嚇了一跳 56325,這就出大問題了,B心想,A是我鐵哥們兒,肯定不會(huì)騙我,肯定是那個(gè)地方數(shù)據(jù)出錯(cuò)了,于是有了下面的對(duì)話

B:兄弟你電腦CPU是什么的?
A:是intel的啊
B:發(fā)送數(shù)據(jù)的時(shí)候有做什么處理嗎?
A:沒有做任何處理
B:額,我明白了

剛好B的機(jī)器也是Intel的CPU,B找到原因之后背了一遍我編寫的口訣,低地址是低位是小端,低低地址是高位為大端。

B分析了一下數(shù)據(jù)的發(fā)送流程,A發(fā)送兩個(gè)字節(jié)的short型數(shù)據(jù),因?yàn)锳是小端所以,先發(fā)送過(guò)來(lái)的是低位數(shù)據(jù),后發(fā)送的是高位,我先接收的也是低位,后接收的是高位。

B修改程序后

int total = (ownMoney[0] &0xFF ) | ( (ownMoney[1] << 8) & 0xFF ) );

一看,額,1500,心里松了一口氣,這就對(duì)了。我們來(lái)看看出現(xiàn)剛剛這個(gè)問題的原因。
A是 Intel CPU (小端機(jī)器), 0x05DC這個(gè)數(shù),低地址存放的是DC,高地址是05, B接受了放在 字符數(shù)組中, 因?yàn)锽也是小端機(jī)器,B還原數(shù)據(jù)的時(shí)候是在低地址放在了高位,也就是0xDC,這是 不對(duì)的。

那總不能每次發(fā)送數(shù)據(jù)都問一下別人是什么CPU吧?

于是人們就約定將數(shù)據(jù)的低地址處放數(shù)據(jù)的高位(也叫大端法),于是A就遵循了這個(gè)約定, 發(fā)送之前將數(shù)據(jù)位置改了一下,因?yàn)橹暗偷刂贩诺氖堑臀弧V癆的數(shù)據(jù)是這樣放的

低地址高地址
DC05

因?yàn)榧s定采用大端法發(fā)送數(shù)據(jù),所以要改成下面這樣

低地址高地址
05DC
//這樣改變位置的代碼 short a = 0x05DC; //用一個(gè)字符指針指向a char* pointerOfA = (char *)&a;//把數(shù)據(jù)的低位值保存在一個(gè)變量里,也就是 DC char temp = *(pointerOfA ); //把高位的值放在低位 *pointerOfA = *(pointerOfA +1); *(pointerOfA +1) = temp;//再發(fā)送 send(sock, pointerOfA ,2,0);

如果遵守約定,B就不用問A你的機(jī)器是什么類型了,但是還有一個(gè)問題,因?yàn)锽的機(jī)器類型可能是大端也可能是小端,那接受數(shù)據(jù)的時(shí)候還要去判斷機(jī)器類型,這也太麻煩了,對(duì),沒錯(cuò),底層的網(wǎng)絡(luò)處理就是這么麻煩。

讓世界更美好

這個(gè)世界變得越來(lái)越美好,是因?yàn)橛星叭藷o(wú)私的付出,計(jì)算機(jī)的世界也一樣,在大小端數(shù)據(jù)轉(zhuǎn)換中也有實(shí)現(xiàn)好了的函數(shù),只等著你去調(diào)用。

htons(unsigned short n):將short轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序 htonl(unsigned long n) : 將long轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序htons 意思就是host to network ,后面一個(gè)代表數(shù)據(jù)類型

還有從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)成本機(jī)字節(jié)序的方法

ntohl ntohs

?

總結(jié)

以上是生活随笔為你收集整理的彻底弄懂计算机中的大端小端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。