這幾天重新看了C語言的基礎(chǔ)知識,感覺內(nèi)存對齊太重要了憎亚,應(yīng)該把它記下來。個(gè)人感覺內(nèi)存對齊是為了適應(yīng)數(shù)據(jù)總線的寬度N弄慰,因?yàn)镃PU從內(nèi)存中取值如果按照N的整數(shù)倍第美,效率會更高。
基本數(shù)據(jù)對齊
32位操作系統(tǒng)
a.一個(gè) char(占用1-byte),變量以1-byte對齊陆爽。
b.一個(gè)short (占用2-byte),變量以2-byte對齊什往。
c.一個(gè)int (占用4-byte),變量以4-byte對齊。
d.一個(gè)long (占用4-byte),變量以4-byte對齊慌闭。
e.一個(gè)float (占用4-byte),變量以4-byte對齊别威。
f.一個(gè)double (占用8-byte),變量以8-byte對齊。
g.一個(gè)long - double (占用12-byte),變量以4-byte對齊驴剔。
h省古,任何pointer (占用4-byte) 變量以4-byte對齊。
64位操作系統(tǒng)
a.一個(gè)long (占用8-byte)變量以8-byte對齊丧失。
b.一個(gè)double (占用8-byte)變量以8-byte對齊
c.一個(gè)long double (占用16-byte) 變量以16-byte對齊
d豺妓、任何pointer (占用8-byte)變量以8-byte對齊。
2布讹、結(jié)構(gòu)體數(shù)據(jù)對齊
結(jié)構(gòu)體數(shù)據(jù)對齊琳拭,是指結(jié)構(gòu)體內(nèi)的各個(gè)數(shù)據(jù)對齊。在結(jié)構(gòu)體中的第一個(gè)成員的首地址等于整個(gè)結(jié)構(gòu)體的變量的首地址描验,而后的成員的地址隨著它聲明的順序和實(shí)際占用的字節(jié)數(shù)遞增白嘁。為了總的結(jié)構(gòu)體大小對齊,會在結(jié)構(gòu)體中插入一些沒有實(shí)際意思的字符來填充(padding)結(jié)構(gòu)體膘流。
在結(jié)構(gòu)體中絮缅,成員數(shù)據(jù)對齊滿足以下規(guī)則:
a鲁沥、結(jié)構(gòu)體中的第一個(gè)成員的首地址也即是結(jié)構(gòu)體變量的首地址。
b盟蚣、結(jié)構(gòu)體中的每一個(gè)成員的首地址相對于結(jié)構(gòu)體的首地址的偏移量(offset)是該成員數(shù)據(jù)類型大小的整數(shù)倍黍析。
c、結(jié)構(gòu)體的總大小是對齊模數(shù)(對齊模數(shù)等于#pragma pack(n)所指定的n與結(jié)構(gòu)體中最大數(shù)據(jù)類型的成員大小的最小值)的整數(shù)倍屎开。
7: struct
8: {
9: char a;
10: int b;
11: short c;
12: char d;
13: }dataAlign;
14:
15: struct
16: {
17: char a;
18: char d;
19: short c;
20: int b;
21:
22: }dataAlign2;
仔細(xì)觀察阐枣,會發(fā)現(xiàn)雖然是一樣的數(shù)據(jù)類型的成員,只不過聲明的順序不同奄抽,結(jié)構(gòu)體占用的大小也不同蔼两,一個(gè)8-byte一個(gè)12-byte。為什么這樣逞度,下面進(jìn)行具體分析额划。
首先來看dataAlign2,第一個(gè)成員的地址等于結(jié)構(gòu)體變量的首地址档泽,第二個(gè)成員char類型俊戳,為了滿足規(guī)則b,它相對于結(jié)構(gòu)體的首地址的偏移量必須 是char=1的倍數(shù)馆匿,由于前面也是char抑胎,故不需要在第一個(gè)和第一個(gè)成員之間填充,直接滿足條件渐北。第三個(gè)成員short=2如果要滿足規(guī)則b阿逃,也不需 要填充,因?yàn)樗钠屏恳呀?jīng)是2赃蛛。同樣第四個(gè)也因?yàn)槠屏縤nt=4恃锉,不需要填充,這樣結(jié)構(gòu)體總共大小為8-byte呕臂。最后來驗(yàn)證規(guī)則c破托,在VC中默認(rèn) 的#pragma pack(n)中的n=8,而結(jié)構(gòu)體中數(shù)據(jù)類型大小最大的為第四個(gè)成員int=4歧蒋,故對齊模數(shù)為4,并且8 mode 4 = 0土砂,所以滿足規(guī)則c。這樣整個(gè)結(jié)構(gòu)體的總大小為8疏尿。
對齊模式n = min(max(struct_member_list),#pragma pack(n))
//當(dāng)#pragma pack(n)中的n大于結(jié)構(gòu)體中最大的成員變量所占內(nèi)存的字節(jié)數(shù)m,即n>m是瘟芝,設(shè)置將毫無意義易桃。
對于dataAlign褥琐,第一個(gè)成員等于結(jié)構(gòu)體變量首地址,偏移量為0晤郑,第二個(gè)成員為int=4敌呈,為了滿足規(guī)則b贸宏,需要在第一個(gè)成員之后填充3-byte,讓它相對于結(jié)構(gòu)體首地址偏移量為4磕洪,結(jié)合運(yùn)行結(jié)果吭练,可知&dataAlign.a = 0x01109140,而&dataAlign.b = 0x01109144析显,它們之間相隔4-byte鲫咽,0x01109141~0x01109143三個(gè)字節(jié)被0填 充。第三個(gè)成員short=2谷异,無需填充滿足規(guī)則b分尸。第四個(gè)成員char=1,也不需要填充歹嘹。結(jié)構(gòu)體總大小相加4 + 4 + 2 + 1 = 11箩绍。同樣最后需要驗(yàn)證規(guī)則c,結(jié)構(gòu)體中數(shù)據(jù)類型大小最大為第二個(gè)成員int=4尺上,比VC默認(rèn)對齊模數(shù)8小材蛛,故這個(gè)結(jié)構(gòu)體的對齊模數(shù)仍然為4,顯然11 mode 4 != 0怎抛,故為了滿足規(guī)則c卑吭,需要在char后面填充一個(gè)字節(jié),這樣結(jié)構(gòu)體變量dataAlign的總大小為4 + 4 + 2 + 2 = 12抽诉。
另外兩道練習(xí)題
typedef struct bb
{
long age; //[0]....[3]
double weight; //[8].....[15] 原則1
float height; //[16]..[19],總長要為8的整數(shù)倍,補(bǔ)齊[20]...[23] 原則3
}BB;
typedef struct aa
{
char name[2]; //[0],[1]
long age; //[4]...[7]
double score; //[8]....[15]
short grade; //[16],[17]
BB b; //[24]......[47]
}AA;
32位系統(tǒng)下面 sizeof(BB) = 24; sizeof(AA) = 48
typedef struct bb
{
long age; //[0]....[7]
double weight; //[8].....[15]
float height; //[16]..[19],總長要為8的整數(shù)倍,補(bǔ)齊[20]...[23]
}BB;
typedef struct aa
{
char name[2]; //[0],[1]
long id; //[8]...[15]
double score; //[16]....[23]
short grade; //[24],[25]
BB b; //[32]......[55] BB結(jié)構(gòu)體的對齊模數(shù)是8陨簇,所以要以32最為開頭
}AA;
64位系統(tǒng)下面 sizeof(BB) = 24; sizeof(AA) = 56
看到這里,以后結(jié)構(gòu)體內(nèi)定義成員變量的順序都要注意了迹淌。
留一個(gè)練習(xí)題:
typedef struct cc
{
long double number1;
BB b;
AA Array[2];
BB * prev;
BB * next;
}CC;
求sizeof(CC) = ??
歡迎提問河绽,不斷更新。??