記憶體對齊 記憶體中的資料對齊 大端模式及小端模式

2021-06-23 02:17:30 字數 3934 閱讀 9244

資料對齊,是指資料所在的記憶體位址必須是該資料長度的整數倍。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整除的位址...