C 記憶體對齊

2021-07-30 16:52:45 字數 3594 閱讀 5506

一,什麼是記憶體對齊

1,計算機中的記憶體是按位元組(byte)劃分的,從理論上講對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別的資料按照一定的規則在記憶體空間上排序,而不是順序的乙個接乙個的排放,這就是記憶體對齊。

2,記憶體對齊是為了讓記憶體訪問更有效率而採用的一種編譯階段優化記憶體訪問的手段。

3,記憶體對齊是指首位址對齊,而不是說每個變數大小對齊。對不同型別的資料,首先計算出它的自身對齊值n,由它的對齊值獲取它在記憶體中的儲存起始位址

,"儲存起始位址  %  n == 0"。

二,與記憶體對齊相關的四個概念

1,基本資料型別自身的對齊值

對於char型別其自身對齊值為1;對於short型別為2;對於int、float、double型別,其自身對齊值為4(

單位/byte)。

2,struct或class的自身對齊值

其成員中自身對齊值最大的那個值。如果某個成員是struct或class,找到這個成員的最大對齊值,然後與獲取的類自身對齊值進行比較,較大的值就是最終的自身對齊值。例如:

struct data;

class people;

struct data裡面的資料型別有char、int、double,那麼struct data應該從8的整數倍開始儲存,因此struct data的自身對齊值為8。class people裡面有乙個成員是struct data,class people裡面包含的基本資料型別成員的最大自身對齊值為4(int),小於struct data,因此class people的自身對齊值為8。

3,指定對齊值

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

4,基本資料型別、結構體和類的有效對齊值

自身對齊值和指定對齊值中小的那個值。

三,對齊值的作用

1,有了上面的這些值,就可以討論具體資料結構的成員和其自身的對齊方式。

有效對齊值n是最終用來決定資料存放位址方式的值。有效對齊值n,就是表示對齊在n上,也就是說該資料的"儲存起始位址  %  n == 0"。

2,計算資料的儲存起始位置

例如:對於struct a,它的對齊值是8,則struct a在記憶體中的"儲存起始位址  %  8 == 0"。struct b中包含乙個型別為struct a的成員,如何計算型別為struct a的

成員儲存位置?

struct a;

struct b; //記憶體大小:sizeof(b) = (2 + 6) + 16 = 24;

short為兩個位元組,儲存short s的位置為[0] - [1],由於struct a的對齊值為8,因此,成員a a的儲存起始位置為8的倍數,成員a a的儲存起始位置為8,儲存位置為[8] - [23]。

3,完成struct或class的收尾工作

例如:對於struct d,它的對齊值為8,則整個struct d的大小應為8的整數倍

struct d;               //記憶體大小:sizeof(d) = 8 + 4 + 2 + 2(補全的2個位元組) = 16;

四,記憶體對齊的三個原則

1,資料成員對齊規則:class、struct、union的資料成員,第乙個資料成員放在offset為0的地方,之後的資料成員的儲存起始位置都是放在該資料成員大小的整數倍位置。如在32bit的機器上,int的大小為4,因此int儲存的位置都是4的整數倍的位置開始儲存。

2,結構體作為資料成員的對齊規則:在乙個struct中包含另乙個struct,內部struct應該以它的最大資料成員大小的整數倍開始儲存。如 struct a 中包含 struct b,struct b 中包含資料成員 char、 int、double,則 struct b 應該以sizeof(double) = 8的整數倍為起始位址。

3,收尾工作的對齊規則:整個struct的大小,應該為最大資料成員大小的整數倍。

五,例項演示

1,struct a的記憶體大小

struct a;                 //記憶體大小:sizeof(a) = (1 + 7) + 8 + (4 + 4) = 24;

2,struct b的記憶體大小,struct b中含有的成員與struct a中的成員相同,但是宣告的順序是不同的

struct b;                 //記憶體大小:sizeof(b) = (1 + 3) + 4 + 8 = 16;

3,struct c的記憶體大小,struct c中含有陣列

struct c;                 //記憶體大小:sizeof(c) = (2 + 2) + (20 * 4 + 4) + 8

4,struct d的記憶體大小,struct d的乙個成員是struct b型別

struct b;

struct d; //記憶體大小:sizeof(d) = (2 + 6) + 16 + (4 + 4) = 32;

六,為什麼要進行記憶體對齊?

a,平台原因(移植原因):

不是所有的硬體平台都能訪問任意位址上的任意資料的,某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。

b,效能原因:

cpu把記憶體當成是一塊一塊的,塊的大小可以是2,4,8,16位元組大小,因此cpu在讀取記憶體時是一塊一塊進行讀取的。塊大小成為memory access granularity(記憶體讀取粒度)。經過記憶體對齊後,cpu的記憶體訪問速度大大提公升。例如,cpu要讀取乙個int型4位元組大小的資料到暫存器中,分兩種情況討論:

1,資料從0位元組開始

該資料是從0位元組開始時,cpu只需讀取記憶體一次即可把這4位元組的資料完全讀取到暫存器中。

2,資料從1位元組開始

當該資料是從1位元組開始時,問題變的有些複雜,此時該int型資料不是位於記憶體讀取邊界上,這就是一類記憶體未對齊的資料。此時cpu先訪問一次記憶體,讀取[0] - [3]位元組的資料進暫存器,並再次讀取[4] - [7]位元組的資料進暫存器,接著把0位元組和5、6、7位元組的資料剔除,最後合併1、2、3、4位元組的資料進暫存器。對乙個記憶體未對齊的資料進行了這麼多額外的操作,大大降低了cpu效能。

C 記憶體對齊

vc6.0編譯器對記憶體對齊的管理方式遵循以下兩個原則 1.對於結構體內部變數的對齊方式 變數存放的起始位址相對於結構的起始位址的偏移量 char 偏移量必須為sizeof char 即1的倍數 int 偏移量必須為sizeof int 即4的倍數 float 偏移量必須為sizeof float ...

c 記憶體對齊

一.計算struct的size有兩個原則 pragma pack n n是編譯器的對齊位元組數 1 struct中各成員按照對齊原則 在為當前變數 設為a 分配記憶體時,要參考之前所有變數的偏移量之和 設為d d必須是min n,sizeof a 的倍數,否則編譯器會自動在最後補上缺少的位元組數。2...

C 記憶體對齊

c 中的記憶體對齊 記憶體對齊 在我們的程式中,資料結構還有變數等等都需要占有記憶體,在很多系統中,它都要求記憶體分配的時候要對齊,這樣做的好處就是可以提高訪問記憶體的速度。我們還是先來看一段簡單的程式 程式一 1 include 2 using namespace std 3 4structx1 ...