#pragma pack()
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack()
#pragma pack(8)
struct A
{
int n;
char c;
short s;
};
struct B
{
char c;
int n;
short s;
};
#pragma pack()
sizeof test:16
sizeof a:8
sizeof b:12
編譯器默認的成員對齊值是8字節(jié),通過#pragma pack(show)指令,編譯的時候在輸出欄會限制默認對齊值。以上程序運行完通過調(diào)試的內(nèi)存察看功能得到a和b的內(nèi)存存儲區(qū)域如下:
a的存儲區(qū)域:0x0012FED0 02 00 00 00 31 00 03 00
b的存儲區(qū)域:0x0012FEBC 31 00 00 00 02 00 00 00 03 00 00 00
最前面的4字節(jié)整數(shù)是變量的起始地址,后面是變量的整個存儲區(qū)域。
現(xiàn)在我們按照 align of member = min( pack setting value, sizeof(member) )的公式分析一下a和b的存儲。
a的第一個成員n為int,大小為4,align of a.n = min(8,sizeof(int) ),對齊值為4。第一個成員相對于結(jié)構(gòu)體起始地址從0偏移開始,前四個字節(jié)02 00 00 00即為n的存儲區(qū)域,因為x86是Little Endian(低字節(jié)在前)的字節(jié)順序,所以第一字節(jié)是2,后面三個字節(jié)0,我們通常寫成0x00000002;
a的第二個成員c為char,大小為1,align of a.c=min(8,sizeof(char)),對齊值為1。c緊接著a后面存儲從偏移4開始,滿足1字節(jié)對齊的要求。它的值為'1',ASCII碼為0x31,共一個字節(jié)31;
a的第三個成員為short,大小為2,align of a.s=min(8,sizeof(short)),對齊值為2。如果緊接第二個成員從偏移5開始存儲就不滿足2字節(jié)對齊,因此跳過1個字節(jié),從偏移6字節(jié)的地方開始存儲,即最后兩個字節(jié)03 00;
b的第一個成員c為char,大小為1,align of a.c=min(8,sizeof(char)),對齊值為1。第一個成員從偏移起始地址0字節(jié)開始存儲,它的值為'1',ASCII碼為0x31,共一個字節(jié)31;
b的第二個成員n為int,大小為4,align of a.n = min(8,sizeof(int) ),對齊值為4。如果緊接第二個成員后面從偏移1開始存儲就不能4字節(jié)對齊,因此跳過3個字節(jié),從偏移4字節(jié)的地方開始存儲,即第5-8的四個字節(jié)02 00 00 00;
b的第三個成員為short,大小為2,align of a.s=min(8,sizeof(short)),對齊值為2。緊接第二個成員從偏移8字節(jié)的地方開始存儲,即9-10兩個字節(jié)03 00;
這時有人可能要問,b為什么最后多了兩個字節(jié)00 00呢?這就是我們下面要講的,整個結(jié)構(gòu)體的對齊。
2、align指令
align指令可以用于設置各種內(nèi)置類型、自定義類型如struct、union或class的的對齊方式。指令格式為:__declspec(align(#)) ,#是對齊值,取值為2的1次方至2的8192次方。在聲明自定義類型或內(nèi)置變量時,如果指定了對齊值,則對應變量的起始地址必須是該值的整數(shù)倍。除此外,它還會影響結(jié)構(gòu)體的大小。下面引用兩段MSDN關(guān)于align的描述:
Without __declspec(align(#)), Visual C++ aligns data on natural boundaries based on the size of the data, for example 4-byte integers on 4-byte boundaries and 8-byte doubles on 8-byte boundaries. Data in classes or structures is aligned within the class or structure at the minimum of its natural alignment and the current packing setting (from #pragma pack or the /Zp compiler option).
從這段可以看出,如果沒有設置align(#)值,變量x按照sizeof(x)來對齊起始地址。類或結(jié)構(gòu)體內(nèi)的成員在類或結(jié)構(gòu)體內(nèi)部按照min( pack setting value,sizeof(member))來對齊。這個我們在pack指令部分已經(jīng)分析過。
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.
從這段可以看出,align(#)指令會影響結(jié)構(gòu)體或類的大小。總結(jié)公式為:
sizeof(structure) = (結(jié)構(gòu)體最后一個成員的偏移 + sizeof(結(jié)構(gòu)體最后一個成員) ) 上取整 ( n* max( 結(jié)構(gòu)體各成員的對齊值,align(#)設置的值 ) ); 其中n為正整數(shù)。
根據(jù)該公式我們分析一下b為什么后面會多兩個填充字節(jié)0。
b的最后一個成s偏移為8,大小為2,b中各成員對齊值最大的為4,因為未設置align(#),所以上取整的數(shù)值為4n。8+2按4的倍數(shù)上取整為12。因此后面需要填充兩個字節(jié),這樣才能使sizeof(b) == 12。
只有注冊用戶登錄后才能發(fā)表評論。 | ||
![]() |
||
網(wǎng)站導航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
|
||
相關(guān)文章:
|
||