首先由乙個程式引入話題: 1
//環境:
vc6 + windows sp2
2//程式13
#include 45
using
namespace
std;67
struct
st1 8;
1314
struct
st215;20
21int
main()
2227
程式的輸出結果為:
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相同,讀者可自己完成。
記憶體對齊的主要作用是:
1、平台原因
(移植原因
):不是所有的硬體平台都能訪問任意位址上的任意資料的;某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。
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先訪問一次記憶體,讀取
0—3位元組的資料進暫存器,並再次讀取
4—5位元組的資料進暫存器,接著把
0位元組和6,
7,8位元組的資料剔除,最後合併1,
2,3,
4位元組的資料進暫存器。對乙個記憶體未對齊的資料進行了這麼多額外的操作,大大降低了
cpu效能。
這還屬於樂觀情況了,上文提到記憶體對齊的作用之一為平台的移植原因,因為以上操作只有有部分
cpu肯幹,其他一部分
cpu遇到未對齊邊界就直接罷工了。
關於記憶體對齊
資料傳送到網路板的資料報大小根本不是實際控制數 據包的大小 這時我才想起乙個人,stanley b.lippman,他寫的那 一本書 inside object modale 曾經提過這樣的事 情,編譯器為了提高cpu的效率,會對struct 的結構進行優化,利用sizeof 可以得出不同的計算機上...
關於記憶體對齊
早上看了乙個貼的面試題,struct st int i short s char c sizeof struct st 是多少?int 4,short 2,char 1,但是sizeof st 是8。這個就是記憶體對齊 再來看個例子 struct strt1 strt1 s1 假設s1.c1位址為0...
關於記憶體對齊
資料傳送到網路板的資料報大小根本不是實際控制資料報的大小 這時我才想起乙個人,stanley b.lippman,他寫的那一本書 inside object modale 曾經提過這樣的事情,編譯器為了提高cpu的效率,會對struct 的結構進行優化,利用sizeof 可以得出不同的計算機上對 s...