1. 程式人生 > 其它 >記憶體對齊 --12.12 學習筆記

記憶體對齊 --12.12 學習筆記

技術標籤:練習指標c++程式語言c語言

我們知道記憶體的最小單元是一個位元組,當cpu從記憶體中讀取資料的時候,是一個一個位元組讀取,所以記憶體對我們應該是入下圖這樣:

但是實際上cpu將記憶體當成多個塊,每次從記憶體中讀取一個塊,這個塊的大小可能是2、4、8、16等,

那麼下面,我們來分析下非記憶體對齊和記憶體對齊的優缺點在哪?

記憶體對齊是作業系統為了提高訪問記憶體的策略。作業系統在訪問記憶體的時候,每次讀取一定長度(這個長度是作業系統預設的對齊數,或者預設對齊數的整數倍)。如果沒有對齊,為了訪問一個變數可能產生二次訪問。

至此大家應該能夠簡單明白,為什麼要簡單記憶體對齊?

  1. 提高存取資料的速度。比如有的平臺每次都是從偶地址處讀取資料,對於一個int型的變數,若從偶地址單元處存放,則只需一個讀取週期即可讀取該變數;但是若從奇地址單元處存放,則需要2個讀取週期讀取該變數。
  2. 某些平臺只能在特定的地址處訪問特定型別的資料,否則丟擲硬體異常給作業系統。

如何記憶體對齊

  1. 對於標準資料型別,它的地址只要是它的長度的整數倍。
  2. 對於非標準資料型別,比如結構體,要遵循一下對齊原則:

1. 陣列成員對齊規則。第一個陣列成員應該放在offset為0的地方,以後每個陣列成員應該放在offset為min(當前成員的大小,#pargama pack(n))

整數倍的地方開始(比如int在32位機器為4位元組,#pargama pack(2),那麼從2的倍數地方開始儲存)。

2. 結構體總的大小,也就是sizeof的結果,必須是min(結構體內部最大成員,#pargama pack(n))的整數倍,不足要補齊。

3. 結構體做為成員的對齊規則。如果一個結構體B裡巢狀另一個結構體A,還是以最大成員型別的大小對齊,但是結構體A的起點為A內部最大成員的整數倍的地方。(struct B裡存有struct A,A裡有char,int,double等成員,那A應該從8的整數倍開始儲存。),結構體A中的成員的對齊規則仍滿足原則1、原則2。

手動設定對齊模數:

    1. #pragma pack(show)

顯示當前packing alignment的位元組數,以warning message的形式被顯示。

    1. #pragma pack(push)

將當前指定的packing alignment陣列進行壓棧操作,這裡的棧是the internal compiler stack,同事設定當前的packing alignment為n;如果n沒有指定,則將當前的packing alignment陣列壓棧。

    1. #pragma pack(pop)

從internal compiler stack中刪除最頂端的reaord; 如果沒有指定n,則當前棧頂record即為新的packing alignement數值;如果指定了n,則n成為新的packing alignment值

    1. #pragma pack(n)

指定packing的數值,以位元組為單位,預設數值是8,合法的數值分別是1,2,4,8,16。

下面是我個人的一些程式碼段 ,不懂的可以加我微信或者直接再CSDN上練習我哦

#include <stdio.h>
#include <stdlib.h> 
					//本機的對齊模數是8  其他電腦可能不同,輸出結果可能有誤!!
					 
/* 	#pragma pack(show)   顯示當前packing alignment的位元組數,以warning message的形式被顯示*/
/* 	#pragma pack(push) 將當前指定的packing alignment陣列進行壓棧操作,這裡的棧是the internal 
compiler stack,同事設定當前的packing alignment為n;如果n沒有指定,則將當前的packing alignment
陣列壓棧。*/
/* 	#pragma pack(pop) 從internal compiler stack中刪除最頂端的reaord; 如果沒有指定n,則當前棧頂
record即為新的packing alignement數值;如果指定了n,則n成為新的packing alignment值*/

typedef struct 
{
	int a; // 0-3
	char b; // 4-7 
	double c;  //8-15
	float d; 	// 20
} Student ;   

Student stu1 ; 
#pragma pack(1)  // 修改現在的記憶體模數 
typedef struct 
{
	int a; // 0-3
	char b; // 4-7 
	double c;  //8-15
	float d; 	// 20
} Student1 ; 

Student1 stu2 ; 
void text01()    // 測試記憶體對齊 
{
	printf("%d\n",sizeof stu1);  // 算出來的sizeof實際上是24  為何呢?  記憶體對齊與對齊模數
	/*所以Student內部對齊之後的大小為20 ,整體對齊,整體為最大類
	型的整數倍 也就是8的整數倍 為24*/
	printf("%d\n",sizeof stu2); 
	
 }
 
#pragma pack(8)
typedef struct 
{
	int a; // 0-3
	Student stuT; 
	double b ;
} Student2 ; 
 
Student2 stu3 ; 
void text02()
{
	printf("%d\n",sizeof stu3);
}
int main(void)
{
	//text01();
	text02();
}