日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

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

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

结构体内存对齐(如何计算结构体的大小)

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

文章目錄

  • 結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則
  • 結(jié)構(gòu)體大小計(jì)算 - 三步曲
  • 為什么存在內(nèi)存對(duì)齊?
  • 設(shè)計(jì)結(jié)構(gòu)體時(shí)的技巧
  • 修改默認(rèn)對(duì)齊數(shù)

結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則

我們知道,整型變量有自己的大小,浮點(diǎn)型變量有自己的大小,數(shù)組也有自己的大小,那么結(jié)構(gòu)體有沒(méi)有自己的大小呢?
回答是肯定的,結(jié)構(gòu)體也有自己的大小,但是結(jié)構(gòu)體的大小并不是簡(jiǎn)單地將每個(gè)結(jié)構(gòu)體成員的大小相加就能得到。

結(jié)構(gòu)體的大小計(jì)算遵循結(jié)構(gòu)體的對(duì)齊規(guī)則

  • 第一個(gè)成員在與結(jié)構(gòu)體變量偏移量為0的地址處。(即結(jié)構(gòu)體的首地址處,即對(duì)齊到0處)
  • 其他成員變量要對(duì)齊到某個(gè)數(shù)字(對(duì)齊數(shù))的整數(shù)倍的地址處。
  • 結(jié)構(gòu)體的總大小為最大對(duì)齊數(shù)(每個(gè)成員變量都有一個(gè)對(duì)齊數(shù))的整數(shù)倍。
  • 如果嵌套了結(jié)構(gòu)體,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍。
  • 對(duì)齊數(shù) = 該結(jié)構(gòu)體成員變量自身的大小與編譯器默認(rèn)的一個(gè)對(duì)齊數(shù)的較小值。
    注:VS中的默認(rèn)對(duì)齊數(shù)為8,不是所有編譯器都有默認(rèn)對(duì)齊數(shù),當(dāng)編譯器沒(méi)有默認(rèn)對(duì)齊數(shù)的時(shí)候,成員變量的大小就是該成員的對(duì)齊數(shù)。

    結(jié)構(gòu)體大小計(jì)算 - 三步曲

    知道了結(jié)構(gòu)體內(nèi)存對(duì)齊規(guī)則,我們就可以計(jì)算結(jié)構(gòu)體的大小了。計(jì)算結(jié)構(gòu)體的大小可分為三個(gè)步驟。我們拿下面這個(gè)結(jié)構(gòu)體舉例:

    struct S {double d;char c;int i; };

    第一步:找出每個(gè)成員變量的大小將其與編譯器的默認(rèn)對(duì)齊數(shù)相比較,取其較小值為該成員變量的對(duì)齊數(shù)。

    注:我使用的是VS編譯器,故默認(rèn)對(duì)齊數(shù)為8。

    第二步:根據(jù)每個(gè)成員對(duì)應(yīng)的對(duì)齊數(shù)畫(huà)出它們?cè)趦?nèi)存中的相對(duì)位置。

    第三步:通過(guò)最大對(duì)齊數(shù)決定最終該結(jié)構(gòu)體的大小。

    通過(guò)圖我們可以知道,綠色部分(double d成員占用)+紅色部分(char c成員占用)+紫色部分(int i成員占用)+紅色與紫色之間的白色部分(浪費(fèi)掉了)總共占用了16個(gè)字節(jié)的內(nèi)存空間。
    我們需要將它們總共占用的內(nèi)存空間(16)與結(jié)構(gòu)體成員的最大對(duì)齊數(shù)(8)相比較,結(jié)構(gòu)體的總大小為最大對(duì)齊數(shù)的整數(shù)倍,此時(shí)16正好是8的整數(shù)倍,所以該結(jié)構(gòu)體在VS編譯器下的大小就16個(gè)字節(jié)。即創(chuàng)建一個(gè)該類(lèi)型的結(jié)構(gòu)體變量,內(nèi)存需為其開(kāi)辟16個(gè)字節(jié)的內(nèi)存空間。

    注意:大多數(shù)情況下,成員變量已經(jīng)占用的總字節(jié)個(gè)數(shù)并不一定正好為其成員變量中的最大對(duì)齊數(shù)的整數(shù)倍,這時(shí)我們需要將其擴(kuò)大為最大對(duì)齊數(shù)的整數(shù)倍。

    為什么存在內(nèi)存對(duì)齊?

    平臺(tái)原因(移植原因): 不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些平臺(tái)只能在某些地址處取得某些特定類(lèi)型的數(shù)據(jù),否則拋出硬件異常。
    比如,當(dāng)一個(gè)平臺(tái)要取一個(gè)整型數(shù)據(jù)時(shí)只能在地址為4的倍數(shù)的位置取得,那么這時(shí)就需要內(nèi)存對(duì)齊,否則無(wú)法訪問(wèn)到該整型數(shù)據(jù)。

    性能原因: 數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能的在自然邊界上對(duì)齊。原因在于,為了訪問(wèn)未對(duì)齊內(nèi)存,處理器需要作兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需一次。

    在畫(huà)圖時(shí)可能有博友會(huì)想,內(nèi)存這么重要,在進(jìn)行內(nèi)存對(duì)齊的時(shí)候怎么還有內(nèi)存被白白浪費(fèi)掉呢?
    現(xiàn)在看來(lái),其實(shí)結(jié)構(gòu)體的內(nèi)存對(duì)齊是拿空間來(lái)?yè)Q取時(shí)間的做法。

    設(shè)計(jì)結(jié)構(gòu)體時(shí)的技巧

    其實(shí)在我們?cè)O(shè)計(jì)結(jié)構(gòu)體的時(shí)候,如果結(jié)構(gòu)體成員的順序設(shè)計(jì)得合理的話,是可以避免不必要的內(nèi)存消耗的。
    兩個(gè)結(jié)構(gòu)體的成員變量相同,但是成員變量的順序不同,可能就會(huì)出現(xiàn)結(jié)構(gòu)體的大小不同的情況:

    struct S1 {char a;char b;int c; };//結(jié)構(gòu)體1 struct S2 {char a;int c;char b; };//結(jié)構(gòu)體2

    我們可以看到,結(jié)構(gòu)體1和結(jié)構(gòu)體2的成員變量一模一樣,可是當(dāng)我們按照內(nèi)存對(duì)齊規(guī)則來(lái)計(jì)算兩個(gè)結(jié)構(gòu)體的大小的時(shí)候,會(huì)發(fā)現(xiàn)兩個(gè)結(jié)構(gòu)體的大小不一樣,在VS編譯器下第一個(gè)結(jié)構(gòu)體大小為8,第二個(gè)結(jié)構(gòu)體大小為12。

    可以見(jiàn)得,結(jié)構(gòu)體成員變量的順序不同,可能會(huì)造成內(nèi)存不必要的損失。將占用空間小的成員盡量集中在一起,可以有效地避免內(nèi)存不必要的浪費(fèi)。

    修改默認(rèn)對(duì)齊數(shù)

    要修改編譯器的默認(rèn)對(duì)齊數(shù),我們需要借助于以下預(yù)處理命令:

    #pragma pack()

    如果在該預(yù)處理命令的括號(hào)內(nèi)填上數(shù)字,那么默認(rèn)對(duì)齊數(shù)將會(huì)被改為對(duì)應(yīng)數(shù)字;如果只使用該預(yù)處理命令,不在括號(hào)內(nèi)填寫(xiě)數(shù)字,那么會(huì)恢復(fù)為編譯器默認(rèn)的對(duì)齊數(shù)。

    #include <stdio.h>#pragma pack(4)//設(shè)置默認(rèn)對(duì)齊數(shù)為4 struct S1 {char a;//1/4->1int b;//4/4->4char c;//1/4->1 };//12 #pragma pack()//取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)#pragma pack(1)//設(shè)置默認(rèn)對(duì)齊數(shù)為1 struct S2 {char a;//1/1->1int b;//4/1->1char c;//1/1->1 };//6 #pragma pack()//取消設(shè)置的默認(rèn)對(duì)齊數(shù),還原為默認(rèn)int main() {printf("%d\n", sizeof(struct S1));//打印結(jié)果為12printf("%d\n", sizeof(struct S2));//打印結(jié)果為6return 0; }

    于是,當(dāng)結(jié)構(gòu)體的對(duì)齊方式不合適的時(shí)候,我們可以自己更改默認(rèn)對(duì)齊數(shù)。

    總結(jié)

    以上是生活随笔為你收集整理的结构体内存对齐(如何计算结构体的大小)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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