一荚恶、結(jié)構(gòu)體變量在內(nèi)存中存放的位置哩牍,也就是對齊方式界阁,默認(rèn)情況下是由編譯器決定的。如果我們需要對其進(jì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ù)(通常是這個類型的大猩)和指定對齊參數(shù)中較小的一個對齊殃姓;
- 結(jié)構(gòu)、聯(lián)合或者類的數(shù)據(jù)成員瓦阐,第一個放在偏移為0的地方蜗侈;以后每個數(shù)據(jù)成員的對齊,按照#pragma pack指定的數(shù)值和這個數(shù)據(jù)成員自身長度兩個中比較小的那個進(jìn)行睡蟋;也就是說踏幻,當(dāng)#pragma pack指定的值等于或者超過所有數(shù)據(jù)成員長度的時候,這個指定值的大小將不產(chǎn)生任何效果戳杀;
- 復(fù)雜類型(如結(jié)構(gòu))整體的對齊<注意是“整體”>是按照結(jié)構(gòu)體中長度最大的數(shù)據(jù)成員和#pragma pack指定值之間較小的那個值進(jìn)行该面;這樣在成員是復(fù)雜類型時,可以最小化長度信卡;
- 結(jié)構(gòu)整體長度的計算必須取所用過的所有對齊參數(shù)的整數(shù)倍隔缀,不夠補(bǔ)空字節(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ù)成員在空間上進(jìn)行對齊见擦,也就是計算結(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)體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值钳宪。