計算結構體占用記憶體,sizeof,指標。

2021-06-26 06:02:31 字數 2986 閱讀 7946

結構體占用內存在好多地方被提及到,特別是在c語言大型開發專案中,利用指標加偏移量來定義乙個新的指標。另外在校招中也經常被提起,這幾天剛好有人問,拿出來研究一下。

在討論結構體內存占用情況之前,先說明一下位元組對齊,正是由於有位元組對齊,有一些看似占用一樣記憶體的結構體實際占用記憶體不同。計算機的記憶體空間是用位元組(byte)劃分的,從理論上講似乎任何型別的變數的訪問都可以從任何位置開始,但是這樣嚴重影響到資料訪問取的效率,於是在計算中位元組按照一定規則在空間中排列,這就是位元組對齊。

位元組對齊的細節一般與具體編譯器有關,但一般而言,滿足三個準則:

1.結構體變數的首位址能夠被其最寬基本型別成員的大小所整除。

2.結構體每個成員相對於結構體首位址的偏移量是成員本身的整數倍,如果有需要編譯器會在成員之間加上填充位元組。

3.結構體的總大小為結構體最寬基本型別成員大小的整數倍,如果有需要編譯器會在最末成員加上填充位元組。

注:這裡所有的對齊細節與編譯器相關是因為每乙個編譯器有預設的對齊位元組數。

因為我們計算的是結構體占用記憶體,所以第一條不考慮,計算機自動會完成。關於第二條和第三條,就著例子計算結構體占用記憶體。

#include #include typedef struct s1s1;

typedef struct s2s2;

int main()

;    s2 s2 = ;

printf("s1:%d\n",sizeof(s1));

printf("s2:%d\n",sizeof(s2));

printf("s1.c1:%d, s1.c2:%d, s2.i:%d\n", &s1.c1, &s1.c2, &s1.i);

printf("s2.c1:%d, s2.i:%d, s2.c2:%d\n", &s2.c1, &s2.i, &s1.c2);

return 0;

}

定義兩個結構體,包含三個變數,兩個char型別的乙個int型別的。

我編譯器中char型別占用1個位元組,short型別佔兩個位元組,int、

float、long

型別占用4個位元組,double占用8位元組。不同編譯器相同型別可能占用位元組數不同,所以先說明一下。

執行結果:

結構體s1占用8個位元組,s2占用12個位元組。

檢視一下在記憶體具體位置,可以看見在s1中c1和c2是連著的,但是c2和i中間有填充位元組;s2中c1占用乙個位元組,後面填充了三個位元組才是資料i的位址,c2後面也填充了三個位元組。

由於每個變數的偏移量要被自身大小所整除,在s1中從首位址2293528開始到2293529偏移了兩個位元組,存c1、c2,如果i資料緊接著儲存的話,資料i的相對首位址的偏移量是2,不能夠被自身整除,所以要填充位元組,填充2個位元組,這樣偏移量是4個位元組,可以被自身整除,這樣s1記憶體大小就是1 + 1 + 2(填充位元組)+ 4 = 8;

同樣s2中,第二個資料是整數型別,偏移量要被自身大小整除所以加了3個填充位元組,這樣計算是1+3(填充位元組)+4+1 = 9,不等於12,是我們計算錯了嗎?不是的,看第三條,結構體占用記憶體總大小要被最寬資料型別整除,如果不滿足,填充位元組。在s2中最寬的資料是整數型i佔4個位元組,我們計算s1占用9個位元組,不能被4整除,所以在最後要填充3個位元組,正好12個位元組能被整除。

在計算結構體占用記憶體時候,先根據第二條計算出結構體占用大小,如果算出的結構體大小不能被最寬資料型別整除,就填充位元組。

如果結構體裡面有陣列怎麼辦?最寬資料型別是按照資料長度計算嗎?

typedef struct s3s3;

int main()

執行結果:

可以想到,如果存在陣列的話,不影響最寬資料型別,陣列還是視為連續儲存的變數。

s3中最寬資料型別是int型別,占用4個位元組,s3中c1[7]占用7個位元組,後面接著是int型別資料,偏移量不能被4整除,填充1個位元組,int型別資料占用8個位元組,最後是char型別資料,占用1個位元組,這樣計算的是7+1(填充位元組)+8+1=17,不能被最寬資料型別整除,填充3個位元組才能整除,所以最後占用記憶體數是7+1(填充位元組)+8+1+3(填充位元組) = 20。

如果存在指標呢?

只要記住指標裡面存的是乙個位址,就明白指標只占用4個位元組。不管指標是指向誰的。

如果結構體中存在結構體呢?最寬資料型別算不算結構體?看一下**:

typedef struct s3s3;

typedef struct s4s4;

int main()

執行結果:

前面我們計算了s3是占用20個位元組,如果結構體算最寬資料型別的話,明顯這個結果是錯誤的,所以在計算結構體占用類存中,最寬的資料型別是指基本的幾種資料型別,不包括資料和結構體。

s4占用記憶體計算:我們計算過s3占用20個位元組,所以直接拿過來用,s4中第乙個資料是char型別資料佔乙個位元組,但是由於s3是乙個整體不可能在內部填充位元組,而最終占用位元組數要是4的倍數,所以要在s4的第乙個資料後面填充三個位元組。所以就是1+3(填充位元組)+20+4=28。

總結:結構體中每個成員相對於結構體首位址的偏移量是成員本身的整數倍,

結構體的總大小為結構體最寬基本型別成員大小的整數倍,如果不滿足編譯器會新增填充位元組。

最後,提到了結構體,肯定會有聯合體,聯合體的記憶體好理解,占用記憶體大小就是最寬資料大小。

typedef union u1

u1;int main()

執行結果:

sizeof結構體和記憶體對齊

有的時候,在腦海中停頓了很久的 顯而易見 的東西,其實根本上就是錯誤的。就拿下面的問題來看 structt 使用sizeof t 將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個字 節。實踐出真知,在vc6中測試了下,答案確實8個位...

sizeof 結構體 和記憶體對齊

有的時候,在腦海中停頓了很久的 顯而易見 的東西,其實根本上就是錯誤的。就拿下面的問題來看 structt 使用sizeof t 將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個位元組。實踐出真知,在vc6中測試了下,答案確實8個位...

sizeof 結構體 和記憶體對齊

2007年10月4日 king 有的時候,在腦海中停頓了很久的 顯而易見 的東西,其實根本上就是錯誤的。就拿下面的問題來看 struct t 使用sizeof t 將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個位元組。實踐出真知,...