一、結(jié)構(gòu)體變量在內(nèi)存中存放的位置,也就是對齊方式,默認(rèn)情況下是由編譯器決定的。如果我們需要對其進行更改,可以使用:
#pragma pack(n)
表示將結(jié)構(gòu)體中的成員按n字節(jié)的對齊方式存儲;
二、說明
- #pragma pack提供數(shù)據(jù)聲明級別的控制,對定義不起作用
- 調(diào)用pack時不指定參數(shù),n將被設(shè)定為默認(rèn)值
- 一旦改變數(shù)據(jù)類型的alignment,直接效果就是占用memory的減少,但是performance會下降
三、重要規(guī)則
- 復(fù)雜類型中各個成員按照它們被聲明的順序在內(nèi)存中順序存儲,第一個成員的地址和整個類型的地址相同;
- 每個成員分別對齊,即每個成員按自己的方式對齊,并最小化長度;規(guī)則就是每個成員按其類型的對齊參數(shù)(通常是這個類型的大?。┖椭付▽R參數(shù)中較小的一個對齊;
- 結(jié)構(gòu)、聯(lián)合或者類的數(shù)據(jù)成員,第一個放在偏移為0的地方;以后每個數(shù)據(jù)成員的對齊,按照#pragma pack指定的數(shù)值和這個數(shù)據(jù)成員自身長度兩個中比較小的那個進行;也就是說,當(dāng)#pragma pack指定的值等于或者超過所有數(shù)據(jù)成員長度的時候,這個指定值的大小將不產(chǎn)生任何效果;
- 復(fù)雜類型(如結(jié)構(gòu))整體的對齊<注意是“整體”>是按照結(jié)構(gòu)體中長度最大的數(shù)據(jù)成員和#pragma pack指定值之間較小的那個值進行;這樣在成員是復(fù)雜類型時,可以最小化長度;
- 結(jié)構(gòu)整體長度的計算必須取所用過的所有對齊參數(shù)的整數(shù)倍,不夠補空字節(jié);也就是取所用過的所有對齊參數(shù)中最大的那個值的整數(shù)倍,因為對齊參數(shù)都是2的n次方;這樣在處理數(shù)組時可以保證每一項都邊界對齊
四、實例
在相同的對齊方式下,結(jié)構(gòu)體內(nèi)部數(shù)據(jù)定義的順序不同,結(jié)構(gòu)體整體占據(jù)內(nèi)存空間也不同,
如下: 設(shè)結(jié)構(gòu)體如下定義:
struct A
{
int a;
char b;
short c;
};
結(jié)構(gòu)體A中包含了4字節(jié)長度的int一個,1字節(jié)長度的char一個和2字節(jié)長度的short型數(shù)據(jù)一個。所以A用到的空間應(yīng)該是7字節(jié)。但是因為編譯器要對數(shù)據(jù)成員在空間上進行對齊,也就是計算結(jié)構(gòu)整體長度,根據(jù)上面三中的第5點可知,整體長度就是所有對齊參數(shù)中最大的那個值(int 4字節(jié))的整數(shù)倍,此時應(yīng)該為2 * 4 = 8,所以使用sizeof(strcut A)值為8。
現(xiàn)在把該結(jié)構(gòu)體調(diào)整成員變量的順序。
struct B
{
char b;
int a;
short c;
};
這時候同樣是總共7個字節(jié)的變量,但是sizeof(struct B)的值卻是12,
地址分配為:b: 0x0000 0000(0x0000 0000), a: 0x0000 0004(0x0000 0004 ~ 0x0000 0007), c: 0x0000 0008(0x0000 0008 ~ 0x0000 0009);計算結(jié)構(gòu)體整體長度,就是3 * 4 = 12;
下面我們使用預(yù)編譯指令#pragma pack (value)來告訴編譯器,使用我們指定的對齊值來取代缺省的。
#pragma pack (2) /*指定按2字節(jié)對齊,等價于#pragma pack(push,2)*/
struct C
{
char b;
int a;
short c;
};
#pragma pack () /取消指定對齊,恢復(fù)缺省對齊,等價于#pragma pack(pop)/
sizeof(struct C)值是8;地址分配:b: 0x0000 0000;a: 0x0000 0002(根據(jù)對齊規(guī)則,int自身的對齊長度為4,使用pack指定為2,取其中的最小值,也就是2字節(jié)對齊);c: 0x0000 0006; 整體長度。
修改對齊值為1:
#pragma pack (1) /*指定按1字節(jié)對齊*/
struct D
{
char b;
int a;
short c;
};
#pragma pack () /取消指定對齊,恢復(fù)缺省對齊/
sizeof(struct D)值為7。
對于char型數(shù)據(jù),其自身對齊值為1,對于short型為2,對于int,float,long類型,其自身對齊值為4,double,long long類型,其自身對齊值為8,單位字節(jié)。
五、概念
這里面有四個概念值:
1.數(shù)據(jù)類型自身的對齊值:就是上面交代的基本數(shù)據(jù)類型的自身對齊值。
2.指定對齊值:#pragma pack (value)時的指定對齊值value。
3.結(jié)構(gòu)體或者類的自身對齊值:其數(shù)據(jù)成員中自身對齊值最大的那個值。
4.數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。