1. 程式人生 > >初學者對於結構體記憶體對齊與補齊的理解

初學者對於結構體記憶體對齊與補齊的理解

1、問題提出:
剛開始學習結構體的時候,我們通常認為結構體

struct number_1
{
    int a;
    int b;
    int c;
}st1;

佔用空間為sizeof(st1.a)+sizeof(st1.b)+sizeof(st1.c)個,
(在vc++6.0中為4+4+4=12個)(為方便下文均以vc++6.0編譯環境為例),實際操作中也是如此。道理卻不是4+4+4=12的道理。

如:

struct number_2
{
    char a;
    int b;
    double c;
}st2;

這裡寫圖片描述
st2所佔記憶體並非1+4+8=13個,而是16個>13個。這是為什麼?

我們會發現,sizeof(st2)=16,剛好是double型別的二倍,這又是為什麼?
我們將上例改為:

struct number_3
{
    char a;
    int b;
}st3;

這裡寫圖片描述
會發現st3記憶體佔用並非1+4=5個,而是sizeof(st3)=8個,剛好是int型別的二倍,這又是為什麼??
瞭解過結構體記憶體對齊原則以後,初學時的問題才得以解決。

2、結構體在記憶體中的對齊原則:
結構體中包含有相同型別或不同型別的資料型別,如char(1位元組),int(4位元組),double(8位元組),所以結構體記憶體出現了一個對齊原則:

結構體變數中元素是按照定義順序一個一個放到記憶體中去的,但並不是緊密排列的。從結構體儲存的首地址開始,每一個元素放置到記憶體中時,它都會認為記憶體是以它自己的大小來劃分的,因此元素放置的位置一定會在自己寬度的整數倍上開始(以結構體變數首地址為0計算)。

即,當char a時,以char自身大小(一位元組)劃分,a佔有了首地址0一個位元組。但是當int b時,以int自身大小(四位元組)劃分,所以b從四位元組的非負整數倍開始儲存佔用四個位元組,由於首地址0已被佔用,所以b從第四個地址開始佔用四個位元組。同理,當double c時,double也以自身大小(八位元組)劃分記憶體,而前八個(0——7)已被佔用,故c從第八個地址開始佔用八個位元組。如下左圖:
如果去掉中間定義的int b,st2仍然佔16個位元組。因為,double c時,首地址0已被佔用,c不能從0(8的0倍)開始,就只能從8(8的1倍)開始。如下右圖:

這裡寫圖片描述 這裡寫圖片描述

而且,double b之前空著的記憶體,在對齊下原則可以隨意增加變數,記憶體是不會增加的。如下圖:
這裡寫圖片描述

3、記憶體的補齊原則:
當定義結構體為:

struct number_4
{
    char a;
    int b;
    char c;
}st4;

時發現sizeof(st4)=12,而不是4+4+1=9。
這時候就牽扯到一個補齊原則:
在經過對齊原則分析後,檢查計算出的儲存單元是否為所有元素中所佔記憶體最大的元素的長度的整數倍,是,則結束;若不是,則補齊為它的整數倍。

即,當4+4+1=9不是結構體中記憶體最大元素b的整數倍時,要補齊成其整數倍12。如下圖左所示,如果將int換成double,sizeof(st4)=24為最大元素double的整數倍了。如下圖右所示:

這裡寫圖片描述 這裡寫圖片描述

總結:
結構體在記憶體中的儲存遵循著對齊與補齊的原則來儲存。