關於記憶體對齊的面試題

2022-06-01 20:30:08 字數 2515 閱讀 9950

鄭重宣告:本文是筆者根據個人理解所寫,錯誤難免,歡迎拍磚!

請說出如下2種方式,哪種更好,為什麼?

方式一:

void foo(int a, float b, char* ch, double d, float f);

方式二:

structa;

void foo(a* pa);

咋一看,不知道這題想要考什麼,無從下手。其實該題是檢查考生對於記憶體對齊的理解。下面我們先看看關於記憶體的一些知識。

什麼是位元組對齊,

為什麼要對齊

?

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

對齊的作用和原因:各個硬體平台對儲存空間的處理上有很大的不同。一些平台對某些特定型別的資料只能從某些特定位址開始訪問。比如有些架構的cpu在訪問乙個沒有進行對齊的變數的時候會發生錯誤,那麼在這種架構下程式設計必須保證位元組對齊.其他平台可能沒有這種情況,但是最常見的是如果不按照適合其平台要求對資料存放進行對齊,會在訪問效率上帶來損失。比如有些平台每次讀都是從偶位址開始,如果乙個int型(假設為32位系統)如果存放在偶位址開始的地方,那麼乙個讀週期就可以讀出這32bit,而如果存放在奇位址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit資料。顯然在讀取效率上下降很多。

對齊規則

每個特定平台上的編譯器都有自己的預設「對齊係數」(也叫對齊模數,32位gcc 4.7上預設為8,32位vs2010上預設為8)。程式設計師可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一係數,其中的n就是你要指定的「對齊係數」。

規則:1、資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。

2、結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。

3、結合1、2可推斷:當#pragma pack的n值等於或超過所有資料成員長度的時候,這個n值的大小將不產生任何效果。

筆者總結:當用sizeof求結構的大小時,第乙個資料大小始終為該資料的sizeof大小(即偏移位始終為0),與對齊係數無關。下乙個資料的仍為其sizeof的大小,但偏移位為min(資料的sizeof大小,對齊係數)。最後對結構本身進行對齊,即結構的sizeof大小為min(結構中最大資料成員長度,對齊係數)的整數倍。注意: 該規則不適用於有設定位域的結構。

如果我們不想編譯器自動為我們新增補齊位,可以將對齊係數設為1,即

1

#pragma pack(push, 1)2//

code...

3#pragma pack(pop)

例項1(32位gcc 4.7):

#include #include 

using

namespace

std;

//#pragma pack(push, 4)

structa;

//#pragma pack(pop)

intmain()

輸出結果:

048

1624

2832

分析結果:這裡預設對齊係數為8,讀者可以根據上面的規則推算一下,sizeof(a) = 4(a) + 4(b) + 1(c) + 7(偏移位) + 8(d) + 4(pa) + 4(pc) = 32。注意,這裡別忘了結構本身的對齊,上面各個資料成員偏移後的大小剛好是對齊係數8的整數倍,就不需要再進行偏移了。如果將上面的注釋去掉,即將預設對齊係數改為4,想想sizeof(a)的大小?sizeof(a) = 4(a) + 4(b) + 1(c) + 3(偏移位) + 8(d) + 4(pa) + 4(pc) = 28。

這裡的offsetof是檢視資料成員在結構中的偏移位,定義在cstddef檔案中。當你#pragma pack(push,n)改變預設物件係數時,n只能取1、2、4、8、16,將你想要進行記憶體對齊的結構放入#pragma pack(push, n) ... #pragma pack(pop)之間,這樣可以防止將其他的結構也進行記憶體對齊。

現在回到上面的面試題,方式一呼叫不存在記憶體對齊的問題,傳入的資料大小就是其本來的資料大小,而方式二就不一樣了,由於記憶體對齊的原因,將導致傳入的結構大小為32(32位gcc 4.7)個位元組,sizeof(a) = 4(a) + 4(b) + 5(ch) + 3(偏移) + 8(d) + 4 + 4(結構本身對齊偏移) = 32。顯然方式一的效果比較高。

關於記憶體對齊的面試題

鄭重宣告 本文是筆者根據個人理解所寫,錯誤難免,歡迎拍磚!請說出如下2種方式,哪種更好,為什麼?方式一 void foo int a,float b,char ch,double d,float f 方式二 structa void foo a pa 咋一看,不知道這題想要考什麼,無從下手。其實該題...

關於面試題中結構體內存對齊計算總結

原則1 資料成員對齊規則 結構 struct 或聯合 union 的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照 pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。原則2 結構 或聯合 的整體對齊規則 在資料成員完成各自對齊之後,結構 或聯...

經典面試題 之 大小端 記憶體對齊補齊

includestruct s x char c 10 int main x 記憶體對齊大小為8個位元組 union x char c 10 8個位元組x,char佔10個位元組又按4個位元組對齊,則為12,若將int改為long or double or longlong則按8位元組對齊結果為16...