#pragma pack

來源:互聯網
上載者:User
 

這麼複雜的東西,不用中文壓根說不清楚。用英文寫,寫了也等寫火星文。

現在的一些處理器,需要你的資料的記憶體位址必須是對齊(align)的,即使不是必須,如果你對齊的話,啟動並執行速度也會得到提升。雖然對齊會產生的額外記憶體空間,但相對於這個速度的提升來說,是值得的。

所謂對齊,就是地址必須能整除一個整數,這個就是對齊參數(alignment
value)。合法的取值範圍是1、2、4、6、16、……、8192。

怎樣對齊呢?編譯器幫你搞定。

怎樣設定編譯器的對齊呢?用#pragma pack( n
)
__declspec(align(#))

依據它倆,編譯器是咋工作的?這個就是接下來要說的了。

但要說清楚的是,以下內容都是本人依據MSDN、網上文章和運行結果自己所推敲出來的,不能確保其一定正確。推薦自己手動做幾個實驗對其進行驗證。

#pragma pack( n )

不說別的,先直接舉例說明這個n是這麼用的。

#pragma pack( 4 )

struct A

{

char
a;

short
b;

char
c;

};

分配方法:

ü a是第一個,占[0]

ü short大小是2,2比n=4小,用2對齊,即b的地址必須是2的倍數,所以[1]不用,b占[2]、[3]

ü char大小是1,1比n=4小,用1對齊,即c占[4]

ü
算完各資料成員後,總共5B。最後,因為結構體A中最大的元素是2B的short,2比n=4小,保證A的大小可以整除2,所以最後結果是6。

ü 整個struct,記憶體配置情況是:a占[0],b占[2][3],c占[4],[1][5]不用。

 

用MSDN的話一言以蔽之:

“The alignment of a member (except the first one) will be on a
boundary that is either a multiple of n or a multiple of the size
of the member, whichever is smaller.”

翻譯成中文,也就是:

“結構體中的資料成員,除了第一個是始終放在最開始的地方,其它資料成員的地址必須是它本身大小或對齊參數兩者中較小的一個的倍數。”

用數學運算式表示:

AlignedValue=min(sizeof(DataMember),n)

DataMemberAddr=AlignedValue*i,i屬於Z*,且i是可以使DataMemberAddr合法(即保證不跑到上一個資料成員的地址中去)的最小一個Z*。

 

如果你被這些定義搞暈了,你完全可以不理這些定義,只要記住分配方法就行了。

按照這個理論,如果把上面的A的資料成員的順序換一換的話,出現什麼情況呢?

例如:

#pragma pack( 4 )

struct A

{

char
a;

char
c;

short
b;

};

分配方法:

ü a是第一個,占[0]

ü char大小是1,1比n=4小,用1對齊,所以c占[1]

ü short大小是2,2比n=4小,用2對齊,即b占[2][3]

ü
算完各資料成員後,總共4B。最後,因為結構體A中最大的元素是2B的short,2比n=4小,保證A的大小可以整除2,所以最後結果是4。

 

奇怪吧,改變資料成員的順序是可以改變結構體的大小的。

 

特別提出:

ü A ao;
sizeof(ao.a )還是1,sizeof(ao.b )還是2。

ü 如果struct B中含有A的一個對象m_a,
struct B
{

A m_a;

}
則這個m_a對齊參數是A中最大的資料類型的大小(這裡是short的2)和n中較小者。如果這個對齊參數是B中最大的話,最後B的大小也會與這個對齊參數有關。

 

__declspec( align(#) )

__declspec( align(#) )和#pragma pack( n )有密切聯絡。

當一個變數或結構體同時受兩者影響時,前者的優先順序高。

成員的地址決定於前者及後者,其要麼是前者的倍數,要麼是後者的倍數,要麼是成員的大小的倍數,取最小。

結構體最後的大小於前者有關,其要麼是前者的倍數,要麼是結構體中最大位移量的倍數,取最大。

要算出最後結果,必須知道兩者的值或預設值。

 

慣例,直接給例子:

#pragma pack( push, 4 )

__declspec( align(32) )struct D

{

Int
i1;

double
d1;

Int
i2;

Int
i3;

};

ü I1是第一個,占[0][1][2][3]

ü double大小是8,8比n=4大,用4對齊,所以d1占[4][5][6][7][8][9][10][11]。

ü int大小是2,2比n=4小,用2對齊,即i2占[12][13][14][15]

ü int大小是2,2比n=4小,用2對齊,即i3占[16][17][18][19]

ü 到現在為止,計算方法都和上面的幾個例子完全一樣。現在算出成員總共佔了20B,而成員中最大的位移量是4。

ü 當計算結構體的最後大小時,因為結構體接受__declspec( align(32)
)影響,比較4和#,4比#=32小,用32補完,所以最後的大小應該是大於20B最小的32倍數,即32B。

 

現在再定義含有D的E

__declspec( align(16) ) struct E

{

int
i1;

D
m_d;

int
i2;

};

 

#pragma pack( pop )

ü I1是第一個,占[0][1][2][3]

ü m_d受之前的__declspec( align(32)
)影響,優先順序高,位移量是32,用32對齊,所以d1占[32]-[63]。

ü int大小是2,2比n=4小,用2對齊,即i2占[64][65][66][67]

ü 現在算出成員總共佔了68B,而成員中最大的位移量是32。

ü 當計算結構體的最後大小時,因為結構體接受__declspec( align(16)
)影響,比較32和#,32比#=16大,用32補完,所以最後的大小應該是大於68B最小的32倍數,即96B。

 

MSDN:

“The sizeof value for any structure is the offset of the final
member, plus that member's size, rounded up to the nearest multiple
of the largest member alignment value or the whole structure
alignment value, whichever is greater.”

中文:

“sizeof的結果都是結構體中最後的一個成員變數加上它的大小,再加上一個填充容量(padding),這個填充大小是成員變數最大的一個對齊參數或整個結構體的對齊參數的倍數,取哪個決定於哪個對齊參數較大”

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.