溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

發(fā)布時(shí)間:2022-03-04 14:40:15 來源:億速云 閱讀:224 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了“C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析”這篇文章吧。

    一、引例

    到底什么是結(jié)構(gòu)體內(nèi)存對齊,我們用一段代碼來介紹一下

    struct S1
    {
    	char c1;//1字節(jié)
    	int a;//4字節(jié)
    	char c2;//1字節(jié)
    };
    int main()
    {
    	printf("%d\n", sizeof(struct S1));
    	//這里打印12
    }

    先來解釋S1,結(jié)構(gòu)體S1中有2個(gè)char類型,1個(gè)int類型。那按道理應(yīng)該是占2*1+4=6個(gè)字節(jié)啊,為什么打印的是12呢?到這里,我們必須要來了解一下結(jié)構(gòu)體內(nèi)存對齊的規(guī)則:

    1.結(jié)構(gòu)體的第一個(gè)成員永遠(yuǎn)放在結(jié)構(gòu)體起始位置偏移量為0的位置

    對于偏移量你可以這樣理解:數(shù)組下標(biāo)為0的相對它自己偏移量為0,下標(biāo)為1的相對下標(biāo)為0的偏移量為1…
    舉例說明:

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    S1第一個(gè)成員是c1,它會(huì)被放在結(jié)構(gòu)體起始位置偏移量為0的位置,如下圖紅色部分

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    2.從第二個(gè)成員開始,總是放在偏移量為一個(gè)對齊數(shù)的整數(shù)處,對齊數(shù)=編譯器默認(rèn)的對齊數(shù)和變量自身大小的較小值

    對齊數(shù)=min(編譯器默認(rèn)的對齊數(shù),變量自身大小)
    Linux-沒有對齊數(shù),VS下對齊數(shù)默認(rèn)為8

    我們?nèi)砸許1這個(gè)結(jié)構(gòu)體進(jìn)行舉例,結(jié)構(gòu)體第二個(gè)成員是int類型的a,占4個(gè)字節(jié),筆者VS環(huán)境下默認(rèn)對齊數(shù)是8,取兩者較小值是4,那a應(yīng)該放到偏移量為4的倍數(shù)上

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    放到4的倍數(shù)上也就說可以放在偏移量為4這里,偏移量為1,2,3的這3個(gè)空間就白白被浪費(fèi)了。而a是int型占4個(gè)字節(jié),所以會(huì)一直占用到偏移量為7的位置。

    接下來是結(jié)構(gòu)體的第三個(gè)成員,char類型的c2,c2占1個(gè)字節(jié),VS環(huán)境下默認(rèn)對齊數(shù)是8,取較小值為1,也就是說只要是1的倍數(shù)的偏移量都可以放,我們緊接著放在a后面,也就是偏移量8的位置

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    那到這里結(jié)構(gòu)體3個(gè)成員都用完了啊,只有8個(gè)啊,為什么打印是12呢?這里就要涉及結(jié)構(gòu)體內(nèi)存對齊的第3個(gè)規(guī)則

    3.結(jié)構(gòu)體的總大小必須是各個(gè)成員的對齊數(shù)中最大的那個(gè)對齊數(shù)的整數(shù)倍

    我們由前面講解知道結(jié)構(gòu)體三個(gè)成員c1,a,c2對齊數(shù)分別為1,4,1這三個(gè)中最大對齊數(shù)是4,總大小要為4的整數(shù)倍,那這時(shí)候肯定有小伙伴會(huì)問:我們現(xiàn)在不是對齊到8了嘛,8不是4的倍數(shù)嗎?注意!這里說的是空間總大小,而8是所謂的偏移量,偏移量是從0開始算的,到8已經(jīng)有9個(gè)空間了,所以我們這里空間要到12,也就是偏移量到11

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    (后面加上的三個(gè)空間用不到,但是由于規(guī)定還是算在結(jié)構(gòu)體總空間內(nèi))

    二、小試牛刀

    我們再來看一道類似的題目

    代碼如下(示例):

    struct S2
    {
    	char c1;//1字節(jié)
    	char c2;//1字節(jié)
    	int a;//4字節(jié)
    };
    int main()
    {
    	printf("%d\n", sizeof(struct S2));
    	//這里打印8
    }

    首先第一個(gè)結(jié)構(gòu)體成員是char類型的c1,由規(guī)則1,它會(huì)直接被放在偏移量為0的位置
    (圖示灰色部分)

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    第二個(gè)成員是char類型的c2,占1字節(jié),VS下默認(rèn)對齊數(shù)是8,取較小值是1,只要放在偏移量為1的倍數(shù)上即可(任意位置),緊跟著0,放在偏移量為1處(圖示紅色部分)

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    最后一個(gè)成員int類型的a,占4個(gè)字節(jié),VS環(huán)境下默認(rèn)對齊數(shù)是8,取較小者4,放在偏移量為4的整數(shù)倍處,也就是4這里,然后由于int占4個(gè)字節(jié)所以一直占用到偏移量7處

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    再來看看規(guī)則3,結(jié)構(gòu)體的總大小必須是各個(gè)成員的對齊數(shù)中最大的那個(gè)對齊數(shù)的整數(shù)倍,也就是4的倍數(shù),我們現(xiàn)在正好是占8個(gè)空間,8正好是4的倍數(shù),所以就不用再往下浪費(fèi)空間了,打印出8

    三、嵌套結(jié)構(gòu)體的特殊情況

    代碼如下(示例):

    struct S3
    {
    	double d;//double占8字節(jié),默認(rèn)對齊數(shù)8,取較小值,對齊數(shù)8
    	char c;//對齊數(shù)1
    	int i;//對齊數(shù)4
    };
    struct S4
    {
    	char c1;
    	struct S3 s3;
    	double d;
    };
    int main()
    {
    	printf("%d\n", sizeof(struct S4));
    }

    關(guān)于結(jié)構(gòu)體S3我們可以采用和前面S1、S2一樣的方法計(jì)算出來是占16個(gè)字節(jié)空間,我們這里重點(diǎn)討論S4,對S3有興趣的小伙伴可自行求解。

    S4中的第一個(gè)成員c1,按規(guī)則1直接放在偏移量為0處,第二個(gè)成員s3怎么辦呢?這里涉及結(jié)構(gòu)體內(nèi)存對齊的第四個(gè)規(guī)則:

    如果嵌套了結(jié)構(gòu)體的情況,嵌套的結(jié)構(gòu)體對齊到自己的最大對齊數(shù)的整數(shù)倍數(shù)處,結(jié)構(gòu)體的整體大小就是所有最大對齊數(shù)(含嵌套結(jié)構(gòu)體的對齊數(shù))的整數(shù)倍

    s3這個(gè)結(jié)構(gòu)體三個(gè)成員最大對齊數(shù)是8,也就是要對齊到偏移量為8的倍數(shù)處,然后s3是占16個(gè)字節(jié),所以一直占到偏移量23處(s3結(jié)構(gòu)體對齊數(shù)是本身s3結(jié)構(gòu)體三個(gè)成員中最大對齊數(shù))

    ps:在VS環(huán)境中,嵌套結(jié)構(gòu)體的最大對齊數(shù)超過8,仍然用8做最大對齊數(shù)(比默認(rèn)對齊數(shù)大了,取較小值就取默認(rèn)對齊數(shù)了)

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    S4最后一個(gè)成員double類型的d占8字節(jié),默認(rèn)對齊數(shù)8,對齊數(shù)取8,然后放在偏移量為對齊數(shù)的整數(shù)倍處,正好往下放在24處,本身占8字節(jié)所以占到31

    C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析

    偏移量0-31共占32字節(jié),S4中的成員c1,s3,d對齊數(shù)分別為1,8,8所以最大對齊數(shù)是8,32恰是8的倍數(shù),所以這里不用再浪費(fèi)空間來滿足 “結(jié)構(gòu)體的總大小必須是各個(gè)成員的對齊數(shù)中最大的那個(gè)對齊數(shù)的整數(shù)倍”這個(gè)規(guī)則,結(jié)構(gòu)體總大小就是32

    四、關(guān)于為什么存在內(nèi)存對齊

    1.平臺(tái)原因(移植原因):

    不是所有的硬件平臺(tái)都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定的類型的數(shù)據(jù),否則拋出硬件異常

    2.性能原因:

    數(shù)據(jù)結(jié)構(gòu)(尤其是棧),應(yīng)盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅僅需要1次
    總體來說:結(jié)構(gòu)體的內(nèi)存對齊是用空間換時(shí)間

    以上是“C語言中結(jié)構(gòu)體與內(nèi)存對齊的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI