1. 程式人生 > >C/C++ 中struct巢狀的記憶體分配

C/C++ 中struct巢狀的記憶體分配

一、概述

        一直只知道非巢狀結構體的記憶體分配大小,卻沒想過如果結構體有巢狀怎麼辦?星期二參加360的筆試碰到了這樣的題目,自然也就答不上來。今天編碼試了下,得出了結論,在此記錄下。這裡主要探討兩點,非巢狀結構體的記憶體分配問題和結構體巢狀的記憶體分配問題。第一點是第二點的基礎,所以我們先探討非巢狀結構體的記憶體分配。

二、非巢狀結構體

       非巢狀結構體記憶體分配大致遵循兩個原則:

     1.記憶體對齊:即每個成員變數在記憶體中存放的起始地址相對於結構體的起始地址必須是這個成員變數型別所佔位元組的整數倍;之所以這麼做是為了保證存取效率。

     2.整個結構體的大小必須是最大成員變數型別所佔位元組數的整數倍。

     有了這兩個原則,計算結構體的大小就容易了。

    假如有如下結構體:

typedef struct MyStruct
	{
	    char a[2];
	    int  b;
	    double c;
	};

a是char型別的陣列,char型別是1個位元組,所以a就是2個位元組。b是int型別,4個位元組,但偏移量是2,不是4的整數倍,所以需要填充2個位元組,把地址偏移到4。然後再加上b的大小,目前就是8個位元組。c是double型別,8個位元組,偏移地址是8,剛好是double的整數倍,所以加上c的大小,一共就是16個位元組(vs2013環境)。你算對了嗎?

再來一個複雜點的:

 typedef struct MyStruct
	{
		char a[2];
		int  b;
		double c;
		int *Pint;
		char d;
		char*Pchar;
	};
同樣的分析方法,當到Pint的時候,結構體大小是16個位元組,偏移是16。Pint是指標,所以無論什麼型別都是4個位元組,所以+4得20個位元組。然後d為char型別,+1得21個位元組。到Pchar的時候,由於偏移為21不是4的整數倍,需要填充3個位元組到24,在加上Pchar的4個位元組得28個位元組。由於最大成員變數是c,8個位元組,所以結構體大小必須是8的倍數,28還要填充到32個位元組才行,所以該結構體最後大小是32個位元組,你猜對了嗎?

三、巢狀結構體

掌握了非巢狀結構體的大小計算方式,巢狀的也就迎刃而解了,採取同樣方式計算即可,只是稍微要複雜點。

看一個例子:

 typedef struct MyStruct
	{
		char a;
		char b;
		struct str2
		{
			int d;
		} c;
	};
a,b都是char型別,無論怎樣都是對齊的,所以計算十分簡單,一共是2個位元組。c是struct型別,需要計算所包含的成員大小,裡面只有一個d,int型別,4個位元組,因為偏移地址必須是int型別大小的整數倍,所以要先填充2個位元組,得4,然後加上d的大小,得8個位元組。所以結果是8個位元組。你猜對了嗎?

再來一個複雜的例子:

typedef struct MyStruct
	{
		char a;
		int b;
		char c;
		char* d;
		double* e;
		struct str2
		{
			int f;
			char g;
			struct str3
			{
				char* p;
			}n;
		} m;
	};

a佔1個位元組,b因為要對齊,所以要填充3個位元組,得4,然後加上b的4個位元組,得8。c佔1個位元組,得9。d是指標,無論什麼型別都是4個位元組,因為要對齊,所以要填充到12,然後加上d,得16。再加上e得20。m是一個結構體,需要計算,f是int型別,加上4得24。再加上g得25。n是一個結構體,p是4個位元組,因為要對齊,要先填充到28,然後加上4得32個位元組。你猜對了嗎?

然後再來看一個比較有迷惑性的例子

typedef struct MyStruct
	{
		char a;
		char b;
		struct str2
		{
			char c;
			char d;
		};
	};

你覺得應該是多少?4個位元組?

        先告訴大家結論,是2個位元組。請大家仔細看,我只是定義了一個str2的結構體,並沒有申明這個結構體的變數!定義是不會分配記憶體的,所以str2是沒有大小的。那麼a+b的大小就是2個位元組。你猜對了嗎?

注:我的測試環境是:作業系統 window 2008 r2,編譯器 VS2013