C语言结构体内存对齐
結(jié)構(gòu)體內(nèi)存對(duì)齊
如何計(jì)算結(jié)構(gòu)體的大小?
首先得掌握結(jié)構(gòu)體的對(duì)齊規(guī)則:
1.第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。(將第一個(gè)成員放在結(jié)構(gòu)體內(nèi)存的第0處)
2.其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。(從0地址處開(kāi)始,偏移量逐漸增減,每個(gè)字節(jié)加一,第二個(gè)成員開(kāi)始,將成員的字節(jié)大小跟對(duì)齊數(shù)(VS2019編譯器的默認(rèn)對(duì)齊數(shù)是 8)進(jìn)行比較,選兩者中較小的,把該變量放到小的對(duì)齊數(shù)的偏移量地址上)
對(duì)齊數(shù) = 編譯器默認(rèn)的一個(gè)對(duì)齊數(shù)與該成員大小的較小值。
- VS中默認(rèn)的對(duì)齊數(shù)為8
- Linux - 沒(méi)有默認(rèn)對(duì)齊數(shù)的概念
3.結(jié)構(gòu)體總大小為最大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。(如果全部成員自身的的大小已經(jīng)放入內(nèi)存,但最后一個(gè)成員的尾字節(jié)所在的偏移量不是最大對(duì)其數(shù)的整數(shù)倍,則在最后要浪費(fèi)空間直到剛好到整數(shù)倍為止)
4.如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。
struct S { //類型大小 VS默認(rèn)對(duì)齊數(shù) 兩者中小的對(duì)齊數(shù)char c1; // 1 8 1int i; // 4 8 4double d; // 8 8 8 }; int main() {struct S s;printf("%d\n",sizeof(s)); //結(jié)構(gòu)體大小為16,并不是簡(jiǎn)單的變量大小相加 }為什么存在內(nèi)存對(duì)齊?
大部分的參考資料都是這樣說(shuō)的:
1.平臺(tái)原因(移植原因)︰不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
⒉.性能原因︰數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。原因在于,為了訪問(wèn)未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn)。
總體來(lái)說(shuō)︰
結(jié)構(gòu)體的內(nèi)存對(duì)齊是拿空間來(lái)?yè)Q取時(shí)間的做法。
那在設(shè)計(jì)結(jié)構(gòu)體的時(shí)候,我們既要滿足對(duì)齊,又要節(jié)省空間,如何做到∶
1.讓占用空間小的成員盡量集中在一起。
2.修改默認(rèn)對(duì)齊數(shù)
之前我們見(jiàn)過(guò)了#pragma這個(gè)預(yù)處理指令,這里我們?cè)俅问褂?#xff0c;可以改變我們的默認(rèn)對(duì)齊數(shù)。
#pragma pack(2) //設(shè)置默認(rèn)對(duì)齊數(shù)為2 struct s1 {char c1;int i;char c2; }; #pragma pack() //取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)此時(shí)結(jié)構(gòu)體大小為8,如果設(shè)置默認(rèn)對(duì)齊數(shù)為1的話,則成員緊挨著存放,等于沒(méi)有對(duì)齊
offsetof宏:
用于計(jì)算結(jié)構(gòu)體中某變量相對(duì)于首地址的偏移量(以字節(jié)為單位)
函數(shù)原型:offsetof (type,member)
使用:
#include <stdio.h> #include <stddef.h> //需要引入頭文件 struct s1 {char c1;int i;char c2; }; int main() {printf("%d\n", offsetof(struct s1, c1)); //0,C1在偏移量為0的地址處printf("%d\n", offsetof(struct s1, i)); //4,i在偏移量為4的地址處printf("%d\n", offsetof(struct s1, c2)); //8,C2在偏移量為8的地址處return 0; }模擬實(shí)現(xiàn)offsetof宏:
#include <stdio.h> struct A {char a;int b;char c;double d; }; #define OFFSETOF(struct_name,mem_name) (int)&(((struct_name *)0)->mem_name) int main() {//模擬實(shí)現(xiàn)宏offsetofprintf("%d\n", OFFSETOF(struct A, a));printf("%d\n", OFFSETOF(struct A, b));printf("%d\n", OFFSETOF(struct A, c));printf("%d\n", OFFSETOF(struct A, d));return 0; }解釋:定義宏時(shí),將0強(qiáng)制轉(zhuǎn)換為結(jié)構(gòu)體類型,只是0不再是個(gè)整型,而是個(gè)地址,是結(jié)構(gòu)體的首地址,并沒(méi)有真正去創(chuàng)建結(jié)構(gòu)體變量,然后通過(guò)->找到相應(yīng)的結(jié)構(gòu)體變量,&取出該變量的地址,減去0地址,再?gòu)?qiáng)制類型轉(zhuǎn)換為int型,就能輸出變量相對(duì)于首地址的偏移量,這里沒(méi)有減-0,因?yàn)闆](méi)有意義,如果規(guī)定首地址是0x10,那最后強(qiáng)轉(zhuǎn)為int之前就要減去首地址0x10,才是偏移量
總結(jié)
以上是生活随笔為你收集整理的C语言结构体内存对齐的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 寄语
- 下一篇: multisim模拟电路加法器_利用mu