資料對齊,是指資料所在的記憶體位址必須是該資料長度的整數倍。dword資料的記憶體起始位址能被
4除盡,
word
資料的記憶體起始位址能被
2除盡。
x86 cpu
能直接訪問對齊的資料,當它試圖訪問乙個未對齊的資料時,會在內部進行一系列的調整。這些調整對於程式設計師來說是透明的,但是會降低執行速度,所以編譯器在編譯程式時會盡量保證資料對齊。
不同的編譯器記憶體對齊的方式不同。
乙個小例子:在32
位的機器上,資料是以
4位元組為對齊單位,這兩個類的輸出結果為什麼不同?(
vs2008)
[cpp]view plain
copy
#include
using
namespace
std;
class
b ;
class
c ;
int_tmain(
intargc, _tchar* argv)
答案是:3*4=12,2*4=8
分析:在訪問記憶體時,如果位址按4
位元組對齊,則訪問的效率會高很多。
考慮到效能方面,編譯器會對結構進行對齊處理,考慮下面的結構:
struct astruct
;直觀地講,這個結構的尺寸是sizeof(char)+sizeof(int)=6,但是在實際編譯下, 這個結構尺寸預設是
8,因為第二個域
ivalue
會被對齊到第
4個位元組。
注意:位元組對齊是編譯時決定的,一旦決定則不會再改變,因此即使有對齊的因素存在,也不會出現乙個結構在執行時尺寸發生變化的情況。
在本題中:第一種類的資料對齊是下面的情況:
bool ---- ---- ----
------- int ---------
bool ----- ---- ----
第二種類的資料對齊是下面的情況:
------- int ----------
bool bool ---------
所以類的大小分別3*4
和2*4
一般在vc++
中加上#pragma pack(n)
設定記憶體對齊。
我們可以利用#pragma pack()
來改變編譯器的預設對齊方式。
#pragma pack(n) //編譯器將按照
n位元組對齊
#pragma pack() //編譯器將取消自定義位元組對齊方式
在#pragma pack(n)
和#pragma pack()
之間的**按
n位元組對齊。
但是成員對齊有乙個重要的條件,即每個成員按照自己的對齊方式對齊;也就是說雖然指定了按n
位元組對齊,但並不是所有的成員都以
n位元組對齊。
對齊的規則是:每個成員按其型別的對齊引數(通常是這個型別的大小)和指定對齊引數(這裡是n
位元組)中較小的乙個對齊,即
min(n,sizeof(item))
,並且結構的長度必須為所用過的所有對齊引數的整數倍,不夠就補空位元組。
[cpp]view plain
copy
#pragma pack(8)
struct
teststruct4
; struct
teststruct5
; int
_tmain(
intargc, _tchar* argv)
執行結果為:8,24
分析:teststruct4 中,成員a是
1位元組,預設按照
1位元組對齊,指定對齊引數是
8,這兩個值中取1,
a按1位元組對齊;
成員b是4
位元組,預設是按
4位元組對齊,這時就按
4位元組對齊,所以sizeof(teststruct4)應該是8.
teststruct5 中,c和teststruct4中的a一樣,按
1位元組對齊;而
d是個結構,它是
8位元組,對於結構來說,它的預設對齊方式就是其所有成員使用的對齊引數中最大的乙個,teststruct4就是4,所以成員
d就按照
4位元組對齊。成員e是
8位元組,它是預設的
8位元組對齊,和指定的一樣,所以它對齊到
8自己的邊界上,這時,已經使用了
12位元組了,所以又新增了
4位元組的空間,從第
16位元組開始放置成員
e。這時長度為
24,已經可以被
8整除(成員e按
8位元組對齊)。這樣一共使用了
24位元組。
記憶體布局圖如下:
teststruct4 的記憶體布局:
a b
1*** 1111
teststruct5 的記憶體布局:
c d.a d.b e
1*** 1*** 1111 **** 11111111
注意3點:
(1)每個成員按照自己的方式對齊,並能最小化長度
(2)複雜型別(如結構)的預設對齊方式是它最長的成員的對齊方式,這樣在成員是複雜型別時,可以最小化長度。
(3)對齊後的長度必須是成員中最大的對齊引數的整數倍,這樣在處理陣列時可以保證每一項都邊界對齊。
補充:對於陣列,比如說char a[3]
,它的對齊方式和分別寫3個
char
是一樣的,也就是說它還是按
1位元組對齊;如果寫成
typedef char arrary3[3],arrary3
這種型別的對齊方式還是按
1位元組對齊,而不是按它的長度。
但是不論型別是什麼,對齊的邊界一定是1、2
、4、8
、16、32
、64......
中的乙個。
下面來說下大端模式和小端模式
大端模式:認為第乙個位元組是最高位位元組,也就說按照從低位址到高位址的順序存放資料的高位位元組到低位位元組。
小端模式:認為第乙個位元組是最低位位元組,也就是說按照從低位址到高位址的順序存放資料的低位位元組到高位位元組。
假設從記憶體位址0x0000
開始有以下資料:
對應資料:0x12 0x34 0x56 0x78
如果我們去讀取乙個位址為0x0000的4
位元組變數
若位元組序位為小端模式,讀出為:0x78563412
若位元組序位為大端模式,讀出為:0x12345678
一般來說:x86
系列的cpu
都是小端位元組序,
powerpc
通常是大端位元組序。
[cpp]view plain
copy
int_tmain(
intargc, _tchar* argv)
執行結果為:37363534
分析:這裡是小端位元組序
位址從0x0000
開始,那麼
sz在記憶體中的儲存為:
對應的值: 0 1 2 3 4 5 6 7 8 9
對應的值: 48 49 50 51 52 53 54 55 56 57
對應的16
進製:0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39
sz ++p
所以讀取為:0x37363534
記憶體對齊 記憶體對齊規則解釋 記憶體對齊原理
一 記憶體對齊的原因 我們都知道計算機是以位元組 byte 為單位劃分的,理論上來說cpu是可以訪問任一編號的位元組資料的,我們又知道cpu的定址其實是通過位址匯流排來訪問記憶體的,cpu又分為32位和64位,在32位的cpu一次可以處理4個位元組 byte 的資料,那麼cpu實際定址的步長就是4個...
記憶體中的資料對齊
為何要位元組對齊 簡單來說就是提高cpu對記憶體的訪問效率。為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問 然而,對齊的記憶體訪問僅需要一次訪問。比如有些平台每次讀都是從偶位址開始,如果乙個int型 假設為32位系統 存放在偶位址開始的地方 那麼讀乙個週期就可以讀出這32bit,而如果存放在奇位...
C struct記憶體對齊 union的大端小端
系統禁止編譯器在乙個結構的起始位置跳過幾個位元組來滿足邊界對齊要求,因此所有結構的起始儲存位置必須是結構中邊界要求最嚴格的資料型別所要求的位置。如某個機器的整型長度為4個位元組且它的起始儲存位置能夠被4整除,那麼結構體 struct allgn 在記憶體中的儲存的起始位置必須是乙個能夠被4整除的位址...