天天看點

位元組對齊問題詳解

位元組對齊,我的了解就是用空間換取時間,提高存取的效率。下面詳細分析:

1.什麼是位元組對齊?

現代計算機中記憶體空間都是按照位元組劃分的,從理論上講似乎對任何類型變量的通路可以從任何位址開始,但實際情況是在通路特定類型變量的時候經常在特 定的記憶體位址通路,這就需要各種類型資料按照一定的規則在空間上排列,而不是順序的一個接一個的排放,這就是位元組對齊。

注意:我們經常聽說的對齊在n上,它的含義就是資料的存放起始位址%n==0。

2.原因及其意義:

各個硬體平台對存儲空間的處理上有很大的不同。一些平台對某些特定類型的資料隻能從某些特定位址開始存取。比如有些架構的cpu在通路 一個沒有進行對齊的變量的時候會發生錯誤,那麼在這種架構下程式設計必須保證位元組對齊。其他平台可能沒有這種情況,但是最常見的是如果不按照适合其平台要求對 資料存放進行對齊,會在存取效率上帶來損失。比如有些平台每次讀都是從偶位址開始,如果一個int型(假設為32位系統)如果存放在偶位址開始的地方,那

麼一個讀周期就可以讀出這32bit,而如果存放在奇位址開始的地方,就需要2個讀周期,并對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit資料。

假設變量test存放在記憶體中的起始位址為0x00,那麼其成員變量ch的起始位址為0x00,成員變量i的起始位址0x01,變量test一共占用了5個位元組。當cpu要對成員變量ch進行通路時,隻需要一個讀周期即可。而如若要對成員變量in進行通路,那麼情況就變得有點複雜了,首先cpu用了一個讀周期,從0x00處讀取了4個位元組(注意由于是32位架構),然後将0x01-0x03的3個位元組暫存,接着又花費了一個讀周期讀取了從0x04-0x07的4位元組資料,将0x04這個位元組與剛剛暫存的3個位元組進行拼接進而讀取到成員變量in的值。為了讀取這個成員變量in,cpu花費了整整2個讀周期。試想一下,如果資料成員i的起始位址被放在了0x04處,那麼讀取其所花費的周期就變成了1,顯然引入位元組對齊可以避免讀取效率的下降,但這同時也浪費了3個位元組的空間(0x01-0x03),即用空間換取了時間。

下面我們講三個重要概念:自身對齊值,指定對齊值和有效對齊值。

①自身對齊值:即資料類型的自身的對齊值。例如char型的資料,其自身對齊值為1位元組;short型的資料,其自身對齊值為2位元組;int,float,long類型,其自身對齊值為4位元組;double類型,其自身對齊值為8位元組;而struct和class類型的資料其自身對齊值為其成員變量中自身對齊值最大的那個值。

②指定對齊值:#pragma pack (value)時指定的對齊值value。

③有效對齊值:min(自身對齊值,指定對齊值)。

3.準則:

其實位元組對齊的細節和具體編譯器實作有關,但一般而言,滿足三個準則:

1) 結構體變量的首位址能夠被其最寬基本類型成員的大小所整除;

2) 結構體每個成員相對于結構體首位址的偏移量都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組。

3) 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充位元組。

4.舉例分析:

對于結構體struct:

首先來看sizeof(struct a),假設a的起始位址為0x00,做這樣的假設隻是為了更友善了解,其實a始終被放在對齊邊界上,這并不影響sizeof的結果,在接下來的例子中,我們也會繼續沿用這個假設。言歸正傳,資料成員c的自身對齊值=1,指定對齊值=4(預設),是以其有效對齊值為1,因0x00%1==0,是以它被存放在0x00處;資料成員i的自身對齊值=4,指定對齊值=4,可得出其有效對齊值為4,因0x01%4

!= 0,是以它應該被存放在0x04位址處,占用0x05,0x06,0x07共4個位元組;接下來看資料成員s的自身對齊值=2,指定對齊值=4,得出有效對齊值為2,因0x08%2 == 0,是以它被存放在起始位址為0x08處,并占用2位元組;最後再看資料結構a自身的對齊值=4(最大資料成員自身對齊值),指定對齊值=4,得有效對齊值為4,因0x0a%4 != 0,是以多占用0x0a和0x0b為結構體a所用(這一步的作用是基于結構體數組的出發,對于結構體或者類,要将它們補充成其有效對齊值的整數倍,這點請千萬注意)。由此可見sizeof(struct

a)的結果應該是=1+3(空閑空間)+4+2+2(結構體補充)=12位元組。

接下來讓我們考察sizeof(struct b)的結果。資料成員c的有效對齊值為1,存放起址0x00,s的有效對齊值為2,存放起址0x02,i的有效對齊值為4,存放起址為0x04,累加起來一共是8個位元組,已經是資料結構b的有效對齊值4的整數倍了。是以sizeof(struct b)的結果8個位元組。

對于聯合體union:

測試結果如下:

8

16

13

14

union就是取整個成員中大的記憶體塊作為整個共用體的記憶體大小。

結論:由于預設是4位元組(32位系統)對齊, 在u1 中a為8位元組,很明顯u1的大小就為8。在u2中由于int為4位元組,char為1 個位元組,是以min(4,max(4,1))=4,以4位元組對齊,u2理論為13個位元組,要以4位元組對齊的話是以為16位元組。同理 u3 :min(max(1,1),4)=1,sizeof(u3)=13, 

u4:min(max(1,4),2)=2,sizeof(u4)=14,

u5:min(max(1,1),2)=1,sizeof(u5)=13。



繼續閱讀