首先由乙個程式引入話題:1//
環境:vc6 + windows sp22//
程式13 #include 45
using
namespace std; 6
7struct st1
8 ; 13
14struct st2
15 ; 20
21int main()
22 27
程式的輸出結果為:
sizeof(st1) is 12
sizeof(st2) is 8
問題出來了,這兩個一樣的結構體,為什麼sizeof的時候大小不一樣呢?
本文的主要目的就是解釋明白這一問題。
記憶體對齊,正是因為記憶體對齊的影響,導致結果不同。
對於大多數的程式設計師來說,記憶體對齊基本上是透明的,這是編譯器該幹的活,編譯器為程式中的每個資料單元安排在合適的位置上,從而導致了相同的變數,不同宣告順序的結構體大小的不同。
那麼編譯器為什麼要進行記憶體對齊呢?程式1中結構體按常理來理解sizeof(st1)和sizeof(st2)結果都應該是7,4(int) + 2(short) + 1(char) = 7 。經過記憶體對齊後,結構體的空間反而增大了。
在解釋記憶體對齊的作用前,先來看下記憶體對齊的規則:
1、 對於結構的各個成員,第乙個成員位於偏移為0的位置,以後每個資料成員的偏移量必須是min(#pragma pack()指定的數,這個資料成員的自身長度) 的倍數。
2、 在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。
#pragma pack(n) 表示設定為n位元組對齊。 vc6預設8位元組對齊
以程式1為例解釋對齊的規則 :
st1 :char佔乙個位元組,起始偏移為0 ,int 佔4個位元組,min(#pragma pack()指定的數,這個資料成員的自身長度) = 4(vc6預設8位元組對齊),所以int按4位元組對齊,起始偏移必須為4的倍數,所以起始偏移為4,在char後編譯器會新增3個位元組的額外位元組,不存放任意資料。short佔2個位元組,按2位元組對齊,起始偏移為8,正好是2的倍數,無須新增額外位元組。到此規則1的資料成員對齊結束,此時的記憶體狀態為:
o***|oooo|oo
0123 4567 89 (位址)
(x表示額外新增的位元組)
共佔10個位元組。還要繼續進行結構本身的對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行,st1結構中最大資料成員長度為int,佔4位元組,而預設的#pragma pack 指定的值為8,所以結果本身按照4位元組對齊,結構總大小必須為4的倍數,需新增2個額外位元組使結構的總大小為12 。此時的記憶體狀態為:
o***|oooo|ooxx
0123 4567 89ab (位址)
到此記憶體對齊結束。st1占用了12個位元組而非7個位元組。
st2 的對齊方法和st1相同,讀者可自己完成。
記憶體對齊的主要作用是:
2、 效能原因:經過記憶體對齊後,cpu的記憶體訪問速度大大提公升。具體原因稍後解釋。
圖一:這是普通程式設計師心目中的記憶體印象,由乙個個的位元組組成,而cpu並不是這麼看待的。
圖二:cpu把記憶體當成是一塊一塊的,塊的大小可以是2,4,8,16位元組大小,因此cpu在讀取記憶體時是一塊一塊進行讀取的。塊大小成為memory access granularity(粒度) 本人把它翻譯為「記憶體讀取粒度」 。
假設cpu要讀取乙個int型4位元組大小的資料到暫存器中,分兩種情況討論:
1、資料從0位元組開始
2、資料從1位元組開始
再次假設記憶體讀取粒度為4。
圖三:當該資料是從0位元組開始時,很cpu只需讀取記憶體一次即可把這4位元組的資料完全讀取到暫存器中。
當該資料是從1位元組開始時,問題變的有些複雜,此時該int型資料不是位於記憶體讀取邊界上,這就是一類記憶體未對齊的資料。
圖四:這還屬於樂觀情況了,上文提到記憶體對齊的作用之一為平台的移植原因,因為以上操作只有有部分cpu肯幹,其他一部分cpu遇到未對齊邊界就直接罷工了。
來自:data alignment: straighten up and fly right
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 ...