記憶體對齊方式

2021-06-17 00:15:55 字數 2655 閱讀 4076

看到這篇博文題目,你可能會想,什麼題目到底啥意思!

首先,你在申請一塊空間時,系統會根據你所申請的空間大小,按照一定規則,給他分配一段空間的起始位址,然後你就可以安心的開始寫你的資料了。今天,這篇博文便是談一談,系統是按照怎麼樣的規則進行分配空間的。

在正式開始之前,我們先小試牛刀:

struct t1

;請問:sizeof(struct t1)的值是多少?

struct t2

;sizeof(struct t2)又是多少?

答案在這先揭曉,我們先看看後面的內容。

1.首先,我們要說一說為什麼要有記憶體對齊這一套機制。

應該普及我們的是,c語言是乙個非常注重效率的語言。在今天,我們記憶體越來越大時,我們可以用以空間為代價,而換取程式高效率的執行。我想這便是記憶體對齊出現的原因吧。我們還是先從例子下手,假設我們有個位址是0x00000001,我們要從接下來的四個位元組裡取乙個int型資料。那按照最快的速度只能這樣:先取乙個位元組的char(0x00000001),然後再取兩個位元組的short(0x00000002 - 0x00000003)然後再取乙個char(0x00000004),如此,才能讀到乙個int值。那麼假設,是從0x00000004

開始讀值的呢!直接乙個四位元組的int不久夠了。這效率比就是三比一了。

2.好了,看了上面的內容你可能就開始想:系統是怎麼對齊的。

對於基本資料型別,其記憶體的首位址為他長度的整數被即可,對於非基本型別,則按照一下方式對齊:

陣列:第乙個元素對齊,後面元素自然就對齊了;

聯合體:以其元素最長的值為對齊值。

結構體:每個資料型別都需要對齊,具體方法如下:

講這問題之前又要補充幾個小名詞:

a.對齊值:即資料的其實位址為d,d%n == 0,n就是他的對齊值。

b.資料型別的自身對齊值:char的自身對齊值就為1,short為2,int float double都為4。

c.結構體和聯合體的自身對齊值:他的對齊值為資料結構中,資料型別的自身對齊值最大的值。

d.指定對齊值:指定對齊值在vc下為#pragra pack(n),其中,n便是所謂的指定對齊值了(gcc,vc 預設對齊值為4)。

e.資料成員或者結構體的有效對齊值:即為指定對齊值和自身對齊值中小的那乙個。

f.有效對齊值圓整:就是結構體占用的總長度必須為其有效對齊值的整數倍。下面給個例子,你可能會更清楚點:

struct a

;假設a分配在0x00000000上,因為int自身對齊值為4,預設的指定對齊也為4,所以a從這裡開始分配4個位元組,那麼,int下乙個元素理論的起始位址為0x00000004,short能不能從這開始分配,我們還需要看看其有效對齊值,經過剛才如上分析得,他的有效對齊值為2,0x00000004明顯是2的整數倍,所以,short就占用0x00000004-0x00000005.難道,sizeof(struct a)為6?不是,我們還需要根據他的有效對齊值圓整,即(4+2 +2)%4 == 0。這就是有效對齊值圓整了。

說到這,部落格前面兩個例題你就有了答案把!

我們分析一下t2好了:首先,假設系統給char分配的空間起始位址為0x00000000,因為char的有效對齊值為1,因此下一元素本是從0x00000001,但是因為下一元素是int,他的有效對齊值是4,系統便要在char後面補三個空位元組了,int從0x000000004開始分配,int下一元素的起始位址為0x00000008,他是short有效對齊值的整數倍,所以short從他開始分配,他占用0x00000008 - 0x00000009.又由於有效對齊值圓整的關係,還有在short後面補齊兩個位元組,所以sizeof(struct t1)為12.同理sizeof(struct t1)為就為8了。從這,可以看出,我們合理定義變數值的順序是可以節省記憶體空間的。

說到這你不禁想問,你怎麼總是假設從0x00000000分配,從0x000000001開始分配,那麼sizeof(struct t1)可能的值就不同了啊。其實,問這個的話,我還真沒有辦法解釋,也沒找到相關資料,只能說說我自己實驗出來的一些東西。假如你的結構體元素長度最長的是char或者short,第乙個元素的起始位址為必為d%4 == 2;若最長為int,那麼其實位址d%4 == 0;若為float或者double,結構體的起始位址d%8 == 0。(當然,我用的是32位機,gcc的編譯環境)。

看到這裡了,我想還有乙個問題得說說,相對與對齊值是資料型別自身屬性而言,我們可以改變指定對齊值。那便是#pragma pack(n);n的值。

比如:

#pragma pack(1)

struct t2

;#pragma pack()

int main(void)

那麼輸出值就是7了。

3.哪些地方可以要設定對齊。

在設計不同cpu下的通訊協議時,或者編寫硬體驅動程式時暫存器的結構這兩個地方都需要按一位元組對齊。即使看起來本來就自然對齊的也要使其對齊,以免不同的編譯器生成的**不一樣

#pragma pack(8)

struct s1

;struct s2

;#pragma pack()

問 1.sizeof(s2) = ?

2.s2的c後面空了幾個位元組接著是d?

理論上來說是24,但是gcc竟然是20(可能還有些問題沒有考慮到,希望大家提點建議),不過還好vc上是24。

推薦博文:講得非常詳細)。

c 記憶體對齊方式

一,什麼是記憶體對齊?記憶體對齊用來做什麼?所謂記憶體對齊,是為了讓記憶體訪問更有效率而採用的一種編譯階段優化記憶體訪問的手段。比如對於int x 這裡假設sizeof int 4 因為cpu對記憶體的讀取操作是對齊的,如果x的位址不是4的倍數,那麼讀取這個x,需要讀取兩次共8個位元組,然後還要將其...

記憶體位址對齊方式

對齊的作用和原因 各個硬體平台對儲存空間的處理上有很大的不同。一些平台對某些特定型別的資料只能從某些特定位址開始訪問。其他平台可能沒有這種情況,但是最常見的是如果不按照適合其平台的要求對資料存放進行對齊,會在訪問效率上帶來損失。比如有些平台每次讀都是從偶位址開始,如果乙個int型 假設為 32位 如...

整數邊界對齊方式 C高階 記憶體對齊

碼字不易,對你有幫助點讚 關注支援一下作者不會程式設計的程式圓看更多乾貨,獲取第一時間更新如果想看比較好看的排版,可以閱讀原文 c高階 四 記憶體對齊 mp.weixin.qq.com 我們這一節主要來講一相關的些比較重要的知識。struct s1 上面是乙個結構體,也是我們自定義的一種型別。我們知...