溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

需要字節(jié)對齊的原因有哪些

發(fā)布時間:2021-10-15 13:52:19 來源:億速云 閱讀:135 作者:iii 欄目:編程語言

這篇文章主要介紹“需要字節(jié)對齊的原因有哪些”,在日常操作中,相信很多人在需要字節(jié)對齊的原因有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”需要字節(jié)對齊的原因有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

字節(jié)對齊

現(xiàn)代計算的內(nèi)存是以字節(jié)來劃分的,理論上可以計算機可以從任意地址開始訪問任意的變量。但實際中,計算機在訪問特定類型變量時,經(jīng)常從特定的內(nèi)存地址訪問,這就需要各種類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,這個規(guī)則,就叫做內(nèi)存對齊。

需要字節(jié)對齊的原因

計算機是通過總線來訪問內(nèi)存的,而總線的寬度一般是32位或者64位,假設(shè)是32位總線,每個總線周期,計算機都會從偶地址開始訪問32位內(nèi)存數(shù)據(jù)。如果一個32位的數(shù)據(jù)沒有存放在4字節(jié)整除的內(nèi)存地址處,那么處理器就需要2個總線周期才能對其進行訪問,自然會降低訪問的效率。所以,為了使CPU能夠?qū)?shù)據(jù)進行快速訪問,數(shù)據(jù)的起始地址應(yīng)具有“對齊”特性。比如4字節(jié)數(shù)據(jù)的起始地址應(yīng)位于4字節(jié)邊界上,即起始地址能夠被4整除。

字節(jié)對齊的分類

字節(jié)對齊分為兩種:

  • 結(jié)構(gòu)體對齊,結(jié)構(gòu)體對齊是字節(jié)對齊的主要對象。

  • 棧對齊,函數(shù)中的局部變量也需要對齊,一般按照4字節(jié)對齊。

結(jié)構(gòu)體字節(jié)對齊

編譯器為結(jié)構(gòu)體的每個成員按照其自然邊界分配空間。

各成員按照他們被聲明的順序在內(nèi)存中順序的存儲。

第一個成員的地址和整個結(jié)構(gòu)體的地址相同。

結(jié)構(gòu)體對齊的4個基本概念

1) 數(shù)據(jù)類型自身的對齊值:char型數(shù)據(jù)自身對齊值為1字節(jié),short型數(shù)據(jù)為2字節(jié),int/float型為4字節(jié),double型為8字節(jié)。
2) 結(jié)構(gòu)體或類的自身對齊值:其成員中自身對齊值最大的那個值。
3) 指定對齊值:#pragma pack (value)時的指定對齊值value。
4) 數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對齊值:自身對齊值和指定對齊值中較小者,即有效對齊值=min{自身對齊值,當前指定的pack值}。

期中,有效對其值N,是最終用來決定數(shù)據(jù)存放地址方式的值。有效對其N表示“對齊在N上”,即該數(shù)據(jù)的“存放起始地址%N=0”。而數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)變量都是按定義的先后順序存放。第一個數(shù)據(jù)變量的起始地址就是數(shù)據(jù)結(jié)構(gòu)的起始地址。結(jié)構(gòu)體的成員變量要對齊存放,結(jié)構(gòu)體本身也要根據(jù)自身的有效對齊值圓整(即結(jié)構(gòu)體成員變量占用總長度為結(jié)構(gòu)體有效對齊值的整數(shù)倍,以便對結(jié)構(gòu)體數(shù)據(jù)進行高效的訪問)。

結(jié)構(gòu)體對齊的3個基本準則

1) 結(jié)構(gòu)體變量的首地址能夠被其最寬基本類型成員的大小所整除;
2) 結(jié)構(gòu)體每個成員相對結(jié)構(gòu)體首地址的偏移量(offset)都是成員大小的整數(shù)倍,如有需要編譯器會在成員之間加上填充字節(jié)(internal adding);
3) 結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要編譯器會在最末一個成員之后加上填充字節(jié){trailing padding}。

第一條:編譯器在給結(jié)構(gòu)體開辟空間時,首先找到結(jié)構(gòu)體中最寬的基本數(shù)據(jù)類型,然后尋找內(nèi)存地址能被該基本數(shù)據(jù)類型所整除的位置,作為結(jié)構(gòu)體的首地址。將這個最寬的基本數(shù)據(jù)類型的大小作為上面介紹的對齊模數(shù)。

第二條:為結(jié)構(gòu)體的一個成員開辟空間之前,編譯器首先檢查預(yù)開辟空間的首地址相對于結(jié)構(gòu)體首地址的偏移是否是本成員大小的整數(shù)倍,若是,則存放本成員,反之,則在本成員和上一個成員之間填充一定的字節(jié),以達到整數(shù)倍的要求,也就是將預(yù)開辟空間的首地址后移幾個字節(jié)。

第三條:結(jié)構(gòu)體總大小是包括填充字節(jié),最后一個成員滿足上面兩條以外,還必須滿足第三條,否則就必須在最后填充幾個字節(jié)以達到本條要求。

不同處理器間的數(shù)據(jù)通信

在不同編譯平臺或處理器上,字節(jié)對齊會造成消息結(jié)構(gòu)長度的變化。

編譯器為了使字節(jié)對齊可能會對消息結(jié)構(gòu)體進行填充,不同編譯平臺可能填充為不同的形式,大大增加處理器間數(shù)據(jù)通信的風險。 

為了解決上述問題,可以按如下方案進行操作:

1)對于本地使用的數(shù)據(jù)結(jié)構(gòu),為提高內(nèi)存訪問效率,采用四字節(jié)對齊方式;
同時為了減少內(nèi)存的開銷,合理安排結(jié)構(gòu)體成員的位置,減少四字節(jié)對齊導(dǎo)致的成員之間的空隙,降低內(nèi)存開銷。
2)對于處理器之間的數(shù)據(jù)結(jié)構(gòu),需要保證消息長度不會因不同編譯平臺或處理器而導(dǎo)致消息結(jié)構(gòu)體長度發(fā)生變化,使用一字節(jié)對齊方式對消息結(jié)構(gòu)進行緊縮;
為保證處理器之間的消息數(shù)據(jù)結(jié)構(gòu)的內(nèi)存訪問效率,采用字節(jié)填充的方式自己對消息中成員進行四字節(jié)對齊。
3)數(shù)據(jù)結(jié)構(gòu)的成員位置要兼顧成員之間的關(guān)系、數(shù)據(jù)訪問效率和空間利用率。
順序安排原則是:四字節(jié)的放在最前面,兩字節(jié)的緊接最后一個四字節(jié)成員,一字節(jié)緊接最后一個兩字節(jié)成員,填充字節(jié)放在最后。

默認的字節(jié)對齊方式

32位機一般默認4字節(jié)對齊(32位機機器字長4字節(jié)),

64位機一般默認8字節(jié)對齊(64位機機器字長8字節(jié)) 。

更改字節(jié)對齊的方式

  • 使用偽指令#pragma pack(n):C編譯器將按照n個字節(jié)對齊;

  • 使用偽指令#pragma pack(): 取消自定義字節(jié)對齊方式。

字節(jié)對齊的方式與sizeof的值

不同的字節(jié)對齊方式,可能影響sizeof的值,在使用sizeof的時候,要認證考慮當前字節(jié)對齊的長度。

在進行網(wǎng)絡(luò)通信的時候,往往需要傳輸一塊buffer,這個buffer的長度,一定要顯示指定,解析的時候也必須使用這個長度。

到此,關(guān)于“需要字節(jié)對齊的原因有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI