日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

C语言结构体内存对齐

發(fā)布時(shí)間:2023/12/20 70 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言结构体内存对齐 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

結(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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。