一、為什麼會有c++記憶體對齊
以下內容節選自《intel architecture 32 manual》。
為了提高程式的效能,資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;然而,對齊的記憶體訪問僅需要一次訪問。
乙個字或雙字運算元跨越了4位元組邊界,或者乙個四字運算元跨越了8位元組邊界,被認為是未對齊的,從而需要兩次匯流排週期來訪問記憶體。乙個字起始位址是奇數但卻沒有跨越字邊界被認為是對齊的,能夠在乙個匯流排週期中被訪問。
二、c++記憶體對齊規則
每個特定平台上的編譯器都有自己的預設「對齊係數」(也叫對齊模數)。程式設計師可以通過預編譯命令#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值的大小將不產生任何效果。
4.各成員變數存放的起始位址相對於結構的起始位址的偏移量必須為該變數的型別所占用的位元組數的倍數。
5.各成員變數在存放的時候根據在結構中出現的順序依次申請空間,同時按照上面的對齊方式調整位置,空缺的位元組自動填充。
6.同時為了確保結構的大小為結構的位元組邊界數(即該結構中占用最大空間的型別所占用的位元組數)的倍數,所以在為最後乙個成員變數申請空間後,還會根據需要自動填充空缺的位元組。
三、pragma pack 巨集
vc中提供了#pragma pack(n)來設定變數以n位元組對齊方式。n位元組對齊就是說變數存放的起始位址的偏移量有兩種情況:第
一、如果n大於等於該變數所占用的位元組數,那麼偏移量必須滿足預設的對齊方式,第
二、如果n小於該變數的型別所占用的位元組數,那麼偏移量為n的倍數,不用滿足預設的對齊方式。結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變數型別所占用的位元組數,那麼結構的總大小必須為占用空間最大的變數占用的空間數的倍數;否則必須為n的倍數。下面舉例說明其用法。
#pragma pack(push) //儲存對齊狀態#pragma pack(4)//設定為4位元組對齊
struct test
; #pragma pack(pop)//恢復對齊狀態
以上結構的大小為16,下面分析其儲存情況,首先為m1分配空間,其偏移量為0,滿足我們自己設定的對齊方式(4位元組對齊),m1占用1個位元組。接著開始為m4分配空間,這時其偏移量為1,需要補足3個位元組,這樣使偏移量滿足為n=4的倍數(因為sizeof(double)大於n),m4占用8個位元組。接著為m3分配空間,這時其偏移量為12,滿足為4的倍數,m3占用4個位元組。這時已經為所有成員變數分配了空間,共分配了16個位元組,滿足為n的倍數。如果把上面的#pragma pack(4)改為#pragma pack(16),那麼我們可以得到結構的大小為24。
記憶體對齊詳解
首先由乙個程式引入話題 程式的輸出結果為 sizeof st1 is 12 sizeof st2 is 8 問題出來了,這兩個一樣的結構體,為什麼sizeof的時候大小不一樣呢?對於大多數的程式設計師來說,記憶體對齊基本上是透明的,這是編譯器該幹的活,編譯器為程式中的每個資料單元安排在合適的位置上,...
記憶體對齊詳解
首先由乙個程式引入話題 1 環境 vc6 windows sp2 2 程式1 3 include 4 5 using namespace std 6 7 struct st1 8 13 14 struct st2 15 20 21 int main 22 23 cout sizeof st1 is ...
C 記憶體對齊詳解
最近看各公司筆試和面試的試題,不少是關於c 記憶體對齊方面的。這個問題我以前也模模糊糊的了解一些,但總是不甚清楚。這次費了很大勁,終於算是搞明白了。整理出來,和大家分享一下。這一切要從機器字長和儲存字長說起。機器字長是cpu每次處理的二進位制的位數 儲存字長是記憶體中乙個儲存單元的包含二進位制位數,...