記憶體對齊到底是怎麼回事?

2021-08-13 18:50:46 字數 3115 閱讀 5885

記憶體對齊問題是各種開發類面試中最熱門的問題,面試管一般認為這個問題可以考察被面試者對記憶體細節的了解情況,確實這個問題對於c++初學者來說是個十足的難題因為它不僅涉及了pragma pack(n) 設定的記憶體對齊係數還涉及了相關記憶體分配的細節。

記憶體對齊:

我們知道現代計算機體系中cpu按照雙字、字、位元組訪問儲存記憶體,並通過匯流排進行傳輸,若未經一定規則的對齊,cpu的訪址操作與匯流排的傳輸操作將會異常的複雜,所以現代編譯器中都會對記憶體進行自動的對齊。

1.記憶體對齊係數

說道記憶體對齊,就不得不說記憶體對齊係數, 對齊係數最簡單的設定方法是使用 #pragma pack(n)進行設定,這部分點進鏈結在我的文章內有詳細說明!

2.sizeof

說到記憶體對齊第二個不得不說的就是sizeof,它的基本作用是判斷資料型別或者表示式長度,要注意的是這不是乙個函式,而是乙個c++中的關鍵字!位元組數的計算在程式編譯時進行,而不是在程式執行的過程中才計算出來!

3.型別的長度與資料成員對齊

你的計算機中,資料型別的長度指的就是在你的計算機中對資料型別使用sizeof得到的結果,當然這個在各種不同的編譯環境下得到的結果是不同的。

比如在32位visual studio環境下:

cout << sizeof(char) << endl;  // 1

cout << sizeof(short) << endl;  // 2

cout << sizeof(int) << endl;  // 4

cout << sizeof(long) << endl;  // 4

cout << sizeof(double) << endl;  // 8

而在64位g++編譯環境下:

cout << sizeof(char) << endl;  // 1

cout << sizeof(short) << endl;  // 2

cout << sizeof(int) << endl;  // 4

cout << sizeof(long) << endl;  // 8

cout << sizeof(double) << endl;  // 8

下面我將在32位visual studio環境下講解資料成員對齊:

首先我們要清楚結構體struct中的成員在記憶體中的分配是連續的,struct內的首位址也就是struct內第乙個資料成員的位址,換句話說struct內第乙個資料成員離struct開始的距離offset = 0。

資料成員對齊的規則就是,而在第乙個成員之後,每個成員距離struct首位址的距離 offset, 都是struct內成員自身長度(sizeof) 與 #pragma pack(n)中的n的最小值的整數倍,如果未經對齊時不滿足這個規則,在對齊時就會在這個成員前填充空子節以使其達到資料成員對齊。

預設n為8時:

#pragma pack(8)

struct mystruct;

cout << sizeof mystruct << endl;  // 16

cout << (int *)&mystruct.a << endl;  // 0024f898

cout << &mystruct.b << endl;  // 0024f8a0(因執行時而異)

當設定n為4也就是min(sizeof(double), n) = 4 時:

#pragma pack(4)

struct mystruct;

cout << sizeof mystruct << endl; // 12

cout << (int *)&mystruct.a << endl; // 0046f76c

cout << &mystruct.b << endl; // 0046f770

第乙個例子時,最小值為8,填充7個位元組到char a 之後。

第二個例子時,最小值為4,填充3個位元組到char a之後。

4.整體對齊

編譯器在進行過資料成員對齊之後,還要進行整體對齊。與資料對齊相似但不是完全相同, 如果資料對齊完成時struct的大小不是 struct內成員自身長度最大值(sizeof) 與 #pragma pack(n)中的n的最小值的整數倍。(注意這裡是成員中長度最大的那個與n比較,而不是特定的乙個成員。)就要在struct的最後新增空位元組直到對齊。

當設定n為4也就是min(sizeof(short), n) = 2 時:

#pragma pack(4)

struct mystruct;

cout << sizeof mystruct << endl;  // 6

cout << (int *)&mystruct.a << endl;  // 003dfed0

cout << &mystruct.b << endl;  // 003dfed2

cout << (int *)&mystruct.c << endl;  // 003dfed4

在上面的例子中,char a offset為0 因成員對齊佔據[d0]填充[d1]共兩個位元組,short b是最大長度成員無需對齊佔據[d2-d3]兩個位元組,它的offset是2,而char c的offset是4佔據[d4]無需成員對齊,但此時struct的大小是2+2+1 = 5位元組,不是2的整數倍,所以我們要填充空子節在最後直到struct大小達到2的整數倍,這就是整體對齊。

經過了資料成員對齊與整體對齊之後記憶體對齊就完成了,如果深入思考上述規則還會發現:即使是同樣數目與數量的資料成員,在擺放的順序不同時struct的大小也會不同,下面就是乙個例子:

這樣擺放是12位元組:

擺放方式改變時結果確變成了8位元組:

炒股到底是怎麼回事?

到底是怎麼回事?很久就聽說 有人賺死,有人虧死。只是聽別人說,自己沒多大興趣,因為聽說風險太大,並且虧的可能性很大,呵呵,誰願意去做八成可能虧的買賣呢?但昨天在sohu上看到一條新聞,引起我對它的興趣,所以今天了解了一下。其實我覺得道理好像很簡單,就是你拿一部分錢跟你兄弟說 兄弟,咱們合夥搞一莊生意...

這到底是怎麼回事呀?

這到底是怎麼回事呀?delphi windows sdk api 怎麼我寫了一段程式,刪除滿足條件的記錄!我已經把requestlive屬性設計有true 怎麼回事!哪位大蝦幫下忙!非常感謝!下面是程式的一小段 按棟刪除學生 if radiobutton6.checked true then beg...

隨機種子 seed()到底是怎麼回事。

讓我們先來看一段 熟悉一下seed 的使用 import numpy as np num 0 while num 5 np.random.seed 1 print np.random.random num 1 print num1 0 np.random.seed 2 while num1 5 pr...