請寫出一下代碼的輸出結果:
// interface.cpp : 定義控制檯應用程序的入口點。
//內存對齊
#include "stdafx.h"
#include <stdio.h>
#include <memory.h>
struct s1
{
int i:8;
char j:4;
int a:4;
double b;
};
struct s2
{
int i:8;
int j:4;
double b;
int a:4;
};
struct s3
{
int i;
char j;
double b;
int a;
};
struct s4
{
int i:8;
int j:4;
int a:3;
double b;
};
struct s5
{
int i:8;
int j:4;
double b;
int a:3;
};
struct name1
{
char str;
short x;
int num;
};
struct name2
{
char str;
int num;
short x;
};
int _tmain(int argc, _TCHAR* argv[])
{
memset((struct s1 *)(0x0012FF48),0,sizeof(struct s1));
struct s1 s;
s.i=1;
s.j=2;
s.a=3;
s.b=3;
printf("%d\t",sizeof(s1));
printf("%d\t",sizeof(s2));
printf("%d\t",sizeof(s3));
printf("%d\t",sizeof(s4));
printf("%d\t",sizeof(s5));
printf("%d\t",sizeof(name1));
printf("%d\t",sizeof(name2));
return 0;
}
按照位域內存對齊規則並參考http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html,分析得知sizeof(s1)=16,而vs2010給出的答案是24,糾結了一下午也沒給出一個明確的答案,先把疑問寫出來,慢慢來求解。
對於比較難解決的問題,最好不要依賴printf,直接按F10,在監視1看了下變量s的地址是0x0012FF48,所以在memset裏會出現0x0012FF48這個地址,爲了把變量s在內存中所佔區域清零,然後在內存1中查看0x0012FF48起始的內存塊,如下圖所示:
從圖中可以看出vs內存對齊規則是4(int)+1(char)+3(擴展)+4(int)+4(擴展)+8(double),很明顯就沒按位域對齊規則來存儲,而是按照普通的一個結構體來進行內存對齊,難道這是vs2010的一個小bug?待求解!
在網上搜索了一番,終於解開了謎題,http://www.diybl.com/course/3_program/c++/cppsl/20090311/160450.html# 這篇文章寫得很好,解釋的很清楚,對於位域存儲規則的處理不同編譯器處理規則不一樣。(以下文字來自於http://www.diybl.com/course/3_program/c++/cppsl/20090311/160450.html#)
如果結構體中含有位域(bit-field),那麼VC中準則又要有所更改:
1)
如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則後面的字段將緊鄰前一個字段存儲,直到不能容納爲止;
2) 如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則後面的字段將從新的存儲單元開始,其偏移量爲其類型大小的整數倍;
3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6採取不壓縮方式(不同位域字段存放在不同的位域類型字節中),Dev-C++和GCC都採取壓縮方式;