1
2
3
4
5
6
|
struct MyStruct { double dda1; char dda; int type; }; |
對齊方式(變量存放的起始地址相對於結構的起始地址的偏移量)
Char
偏移量必須爲sizeof(char)即1的倍數
int
偏移量必須爲sizeof(int)即4的倍數
float
偏移量必須爲sizeof(float)即4的倍數
double
偏移量必須爲sizeof(double)即8的倍數
Short
偏移量必須爲sizeof(short)即2的倍數
默認的對齊方式
1
2
3
4
5
6
|
struct MyStruct { double dda1; char dda; int type; }; |
1
2
3
4
5
6
|
struct MyStruct { char dda; double dda1; int type; }; |
typedef struct bb
{
int id; //[0]....[3] 表示4字節
double weight; //[8].....[15]
float height; //[16]..[19],總長要爲8的整數倍,僅對齊之後總長爲[0]~[19]爲20,補齊[20]...[23]
}BB;
typedef struct aa
{
int id; //[0]...[3]
double score; //[8]....[15]
short grade; //[16],[17]
BB b; //[24]......[47] (因爲BB內部最大成員爲double,即8的整數倍開始存儲)
char name[2]; //[48][49] 50個字節,湊六個,成爲8的倍數
}AA;
int main()
{
cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl;
return 0;
}
輸出結果爲56(補位湊成8的倍數) 24struct s1
{
char a[8];
};
struct s2
{
double d;
};
struct s3
{
s1 s;
char a;
};
struct s4
{
s2 s;
char a;
};
cout<<sizeof(s1)<<endl; // 8
cout<<sizeof(s2)<<endl; // 8
cout<<sizeof(s3)<<endl; // 9
cout<<sizeof(s4)<<endl; // 16;
所以,在自己定義結構體的時候,如果空間緊張的話,最好考慮對齊因素來排列結構體裏的元素。
編譯器中提供了#pragma pack(n)來設定變量以n字節對齊方式。//n爲1、2、4、8、16...
n字節對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大於等於該變量所佔用的字節數,那麼偏移量必須滿足默認的對齊方式,即該變量所佔用字節數的整數倍;第二、如果n小於該變量的類型所佔用的字節數,那麼偏移量爲n的倍數,不用滿足默認的對齊方式。
結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變量類型所佔用的字節數,那麼結構的總大小必須爲佔用空間最大的變量佔用的空間數的倍數;否則必須爲n的倍數。
所以在上面的代碼前加一句#pragma pack(1),
則代碼輸出爲bb:(0~3)+(4~11)+(12~15)=16; aa:(0~1)+(2~5)+(6~13)+(14~15)+(16~31)=32,也就是說,#pragma pack(1)就是沒有對齊規則。
再考慮#pragma pack(4),bb:(0~3)+(4~11)+(12~15)=16; aa:(0~1)+(4~7)+(8~15)+(16~17)+(20~35)=36
4、 32位和64位系統的區別
5、聯合體的sizeof
共用體表示幾個變量共用一個內存位置,在不同的時間保存不同的數據類型和不同長度的變量。在union中,所有的共用體成員共用一個空間,並且同一時間只能儲存其中一個成員變量的值。當一個共用體被聲明時, 編譯程序自動地產生一個變量, 其長度爲聯合中元類型(如數組,取其類型的數據長度)最大的變量長度的整數倍,且要大於等於其最大成員所佔的存儲空間。
union foo
{
char s[10];
int i;
} ;
union mm{
char a;//元長度1 1
int b[5];//元長度4 20
double c;//元長度8 8
int d[3]; 12
};
foo的內存空間的長度爲12,是int型的3倍,而並不是數組的長度10。若把int改爲double,則foo的內存空間爲16,是double型的兩倍。同理,sizeof(mm)=8*3=24;