详解结构体内存对齐
目錄
結(jié)構(gòu)體內(nèi)存對(duì)齊的概念
?結(jié)構(gòu)體內(nèi)存對(duì)齊的規(guī)則
?結(jié)構(gòu)體大小的計(jì)算
第一步:確定每個(gè)成員變量的對(duì)齊數(shù)
?第二步:定位
?第三步:確定該結(jié)構(gòu)體的大小
結(jié)構(gòu)體為什么要內(nèi)存對(duì)齊
VS下修改默認(rèn)對(duì)齊數(shù)?
調(diào)整結(jié)構(gòu)體大小
offsetof函數(shù)的使用
結(jié)構(gòu)體內(nèi)存對(duì)齊的概念
?定義一個(gè)結(jié)構(gòu)體變量
struct S {char c1;//1int i;//4char c2;//1 };int main()printf("%d\n", sizeof(struct S));return 0; }請(qǐng)問sizeof(struct S)是多大呢?有小伙伴會(huì)說無非就是把內(nèi)部成員各自的大小加起來:1+4+1=6,因此答案就是6,可惜答案不是這個(gè),而是12。
為啥相差這么大呢?因?yàn)榻Y(jié)構(gòu)體內(nèi)的成員之間在內(nèi)存中的位置并不是緊挨在一起的。
?即不是這樣的:
?而是這樣的:
?一個(gè)格子代表一個(gè)字節(jié)的大小,從圖中也看不出12是哪里來的,大家細(xì)細(xì)的往下看
?這些成員進(jìn)行了內(nèi)存對(duì)齊,即按照某種規(guī)則將這些成員在內(nèi)存中的位置進(jìn)行了調(diào)整,這種規(guī)則稱之為結(jié)構(gòu)體內(nèi)存對(duì)齊。內(nèi)存對(duì)齊后其外在表現(xiàn)就是struct S這個(gè)結(jié)構(gòu)體類型的大小就會(huì)發(fā)生改變,也就是說結(jié)構(gòu)體大小遵循結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則
?結(jié)構(gòu)體內(nèi)存對(duì)齊的規(guī)則
1.第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。
2.其他成員變量要對(duì)齊到自身對(duì)齊數(shù)的整數(shù)倍的地址處。
? ? ? ? 每個(gè)成員的對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù) 與 該成員大小的較小值。
????????VS中默認(rèn)的值為8(這個(gè)值可以進(jìn)行修改)
????????linux沒有默認(rèn)值,直接以該成員大小為對(duì)齊數(shù)
3.結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(從每個(gè)成員變量的對(duì)齊數(shù)中挑選)的整數(shù)倍。
4.如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。
如果大家看的不是很懂不用擔(dān)心,接下來帶著大家計(jì)算結(jié)構(gòu)體大小?
?結(jié)構(gòu)體大小的計(jì)算
?VS編譯器下,默認(rèn)對(duì)齊數(shù)是8
第一步:確定每個(gè)成員變量的對(duì)齊數(shù)
?
?第二步:定位
?定位:將每個(gè)成員變量在內(nèi)存中的位置確定好
?
?第三步:確定該結(jié)構(gòu)體的大小
?通過上圖發(fā)現(xiàn)內(nèi)存空間已經(jīng)使用了9個(gè)格子即9個(gè)字節(jié),那么結(jié)構(gòu)體大小就是9了嗎?其實(shí)還不是,根據(jù)結(jié)構(gòu)體內(nèi)存規(guī)則:結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。
對(duì)齊數(shù)有1,4,1,最大對(duì)齊數(shù)自然就是4了,那么12比9大,而且是最大對(duì)齊數(shù)4的整數(shù)倍,因此該結(jié)構(gòu)體大小就是12,。
有小伙伴是否有疑問比如16,20也符合比9大,且是最大對(duì)齊數(shù)4的整數(shù)倍,那么為什么選擇12呢?因?yàn)橐M可能的節(jié)省空間的使用啊!于是小伙伴又會(huì)問:節(jié)省空間的使用為什么還要內(nèi)存對(duì)齊呢?不使用內(nèi)存對(duì)齊的時(shí)候該結(jié)構(gòu)體大小是6啊!?接下來幫助大家解釋為什么存在內(nèi)存對(duì)齊
結(jié)構(gòu)體為什么要內(nèi)存對(duì)齊
1.平臺(tái)原因(移植原因): ?不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的;
?? ?某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2.性能原因: 數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。
?? ?原因在于,為了訪問未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對(duì)齊的內(nèi)存訪問僅需要一次訪問。?
?
VS下修改默認(rèn)對(duì)齊數(shù)?
?#pragma pack(num)
//num為具體的數(shù),將默認(rèn)對(duì)齊數(shù)設(shè)置為num大小
#include<stdio.h>#pragma pack(2) //一般設(shè)置為2的次方 struct S{char c1; int i; char c2; };int main(){printf("%d\n", sizeof(struct S));return 0; }?
調(diào)整結(jié)構(gòu)體大小
?
?這里只是調(diào)整了結(jié)構(gòu)體成員變量定義的順序就導(dǎo)致了結(jié)構(gòu)體大小的變化,
如果結(jié)構(gòu)體成員的順序設(shè)計(jì)得合理的話,比如將占用空間小的成員盡量集中在一起是可以避免不必要的內(nèi)存消耗的
?offsetof函數(shù)的使用
?頭文件<stddef.h>
函數(shù)原型:size_t offsetof(type, member);
功能:返回指定成員從一開始的字節(jié)數(shù)偏移量
#include<stdio.h> #include<stddef.h> #pragma pack(2) struct S1{ char c1;char c2;int i; };struct S2 {char c1;int i;char c2; };int main(){printf("struct S1 %d\n", sizeof(struct S1));printf("c1 %d\n", offsetof(struct S1, c1));printf("c2 %d\n", offsetof(struct S1, c2));printf(" i %d\n", offsetof(struct S1, i));printf("struct S2 %d\n", sizeof(struct S2));printf("c1 %d\n", offsetof(struct S2, c1));printf(" i %d\n", offsetof(struct S2, i));printf("c2 %d\n", offsetof(struct S2, c2));return 0; }執(zhí)行結(jié)果:
總結(jié)
- 上一篇: Swift基础学习(二)数据类型
- 下一篇: 点击开启此虚拟机时,出现“该虚拟机似乎正