結構體的內存分配機制


首先,結構在C語言中也是一種數據類型,叫做聚組類型(還包括數組)。他和其他的數據類型是一樣的,在定義一個結構體的時候,系統並不會為他真正的分配內存空間(定義的結構體變量要在編譯的階段才分配空間,而結構體指針要顯示的使用malloca來分配空間),也就是說,在定義結構體這種數據類型的時候是不會分配內存空間的,只有在定義變量的時候,才會分配。

下面是摘自百度百科 對結構題存儲的三點:

1) 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除;  

2) 結構體每個成員相對於結構體首地址的偏移量都是成員大小的整數倍,如有需要編譯器會  在成員之間加上填充字節;

3) 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之后加上填充字節

 

下面是來自《c和指針》的介紹

struct s1{

  char a;

  int b;

  char c;

};

首先,結構體在存儲的時候,結構體的首地址必須能夠被其中最寬數據類型整除。(在s1中,最寬數據類型為int,在32位系統中為4Byte),

 

其次,參照第二條,第一個數據時char(已經保證了,結構的起始地址是4的整數倍),存儲一個char,占一個Byte,要保證下一個int的存儲起始地址是4的整數倍,所以要在char后面填充三個Byte,然后在存儲第三個數據。

第三,最后一個也是char類型,他就占一個Byte,肯定是他存儲位置的整數倍,最后參照第三條,結構體的總大小為最寬數據類型的整數倍,所以會在第二個char之后再填充三個Byte。

這樣的話,總共占據的空間是1+3+4+1+3 = 12(紅色為填充字符)

【但是】,調換一下結構中數據成員的順序

 

struct s1{

  int b;

  char a;

  char c;

};

同樣地分析4+1+1+2 = 8

相比之下,存儲空間的效率提高33%。

 

以下是系統對結構體的內存分配的詳細介紹:

1、結構體變量的首地址是結構體中最寬數據類型的整數倍。

  編譯器在給結構體開辟空間時,首先找到結構體中最寬的基本數據類型,然后尋找內存地址能是該基本數據類型的整倍的位置,作為結構體的首地址。

2、結構體每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節。

  為結構體的一個成員開辟空間之前,編譯器首先檢查預開辟空間的首地址相對於結構體首地址的偏移是否是本成員的整數倍,若是,則存放本成員,反之,則在本成員和上一個成員之間填充一定的字節,以達到整數倍的要求,也就是將預開辟空間的首地址后移幾個字節。

3、結構體的總大小為結構體中最寬基本數據成員的整數倍。如有需要,編譯器將會在結構體的添加填充字符。

4、結構體中的數據成員按照所占空間從大到小的順序來排列的話,這樣存儲空間就會得以提高。

4、現在對四條進行修正。在組織數據結構的數據成員的時候,可以將相同類型的成員放在一起,這樣就減少了編譯器為了對齊而添加的填充字符。

【提示】:

  有些時候,我們不應該對結構的數據成員進行重排以減少因對齊帶來的空間損失。因為在我們對數據成員重拍的時候,往往破壞了數據間的關聯性,從而降低了程序的可讀性和可維護性。

綜上,我們可以得出,在對結構的成員進行重排的時候,即要考慮存儲空間的使用效率,又要考慮程序的可讀性與可維護性。

 

下面的代碼是對上述幾條的驗證:

#include<stdio.h>
#include<stddef.h>
struct s1{
int a;
char b;
char c;
};

struct s2 {
char b;
char c;
int a;

};
int main(){
/*
struct s1 s;
s.a = 12;
s.b = 'a';
s.c = 'b';

printf("int s.a size: %d \n",offsetof(struct s1,a));
printf("char s.b size: %d \n",offsetof(struct s1,b));
printf("char s.b size: %d \n",offsetof(struct s1,c));
printf("size of struct s1: %d\n",sizeof(struct s1));
*/


struct s2 s;
s.a = 12;
s.b = 'a';
s.c = 'b';

printf("int s.a size: %d \n",offsetof(struct s2,a));
printf("char s.b size: %d \n",offsetof(struct s2,b));
printf("char s.b size: %d \n",offsetof(struct s2,c));
printf("size of struct s1: %d\n",sizeof(struct s2));
}

復制代碼
 1 #include<stdio.h>
 2 #include<stddef.h>
 3 struct s1{
 4     int a;
 5     char b;
 6     char c;
 7 };
 8 
 9 struct s2 {
10     char b;
11     char c;
12     int a;
13     
14 };
15 int main(){
16     /*
17     struct s1 s;
18     s.a = 12;
19     s.b = 'a';
20     s.c = 'b';
21 
22     printf("int s.a size: %d \n",offsetof(struct s1,a));
23     printf("char s.b size: %d \n",offsetof(struct s1,b));
24     printf("char s.b size: %d \n",offsetof(struct s1,c));
25     printf("size of struct s1: %d\n",sizeof(struct s1));
26     */
27 
28 
29     struct s2 s;
30     s.a = 12;
31     s.b = 'a';
32     s.c = 'b';
33 
34     printf("int s.a size: %d \n",offsetof(struct s2,a));
35     printf("char s.b size: %d \n",offsetof(struct s2,b));
36     printf("char s.b size: %d \n",offsetof(struct s2,c));
37     printf("size of struct s1: %d\n",sizeof(struct s2));
38 }
復制代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM