1. 程式人生 > 實用技巧 >C語言中結構體變數佔用空間及位元組對齊問題

C語言中結構體變數佔用空間及位元組對齊問題

轉自:https://www.cnblogs.com/jungzhang/p/5547346.html

結構體到底佔多大的空間呢?先看一下下面這道題的輸出結果:

 1 #include<stdio.h>
 2 
 3 typedef struct test
 4 {
 5      char a;
 6      int   b;
 7      double c;
 8 }TEST;
 9 
10 int main(void)
11 {
12      TEST test1;
13      printf("%ld\n",sizeof(test1));
14      
15      return
0; 16 }

不妨大膽猜想,結構體所佔空間是不是其成員所佔空間的代數和呢??按照這個猜想,該題的答案應該為13,然而事實卻讓人大跌眼鏡,本題輸出的結果為16。google一下知這是因為計算機中存在一種叫做記憶體對齊的機制導致了該結果的發生。

在計算機中通常會讓CPU從記憶體中一次讀取若干個位元組的資料,而不是一次只讀取一個位元組的資料,這樣的好處是提高了計算機的效率,然而壞處也顯而易見。

假設CPU一次從記憶體中讀取四個位元組的資料,而現在記憶體中存在一個char型的資料和一個int型的資料,如果記憶體不對齊,當CPU第一次跨越四個位元組定址找到了一個char型的資料,而此時CPU的指向到了int型的中間區域,導致這個int型變數未找到,然後CPU會返回去再次尋找,直到找到該int型變數。這樣不但沒能提高效率,反而增加了CPU的負擔。因此我們通常會在第一個char型變數後邊填充一部分資料來保證每次定址時地址都是該資料的整數倍,這樣就避免了上述“錯誤”的發生,也就是所謂的記憶體對齊。

記憶體對齊的規則很簡單:

一、起始位置為成員資料型別所佔記憶體的整數倍,若不足則不足部分用資料將記憶體填充為該資料型別的整數倍。

二、結構體所佔總記憶體為其成員變數中所佔空間最大資料型別的整數倍。

假設上題中結構體變數是從零號記憶體開始儲存,則char型變數佔一個位元組,而後int型變數發現起始位置在一號記憶體處,並不滿足起始位置為int型所佔4位元組整數倍的要求,故將一二三號記憶體填充滿,從四號記憶體處開始儲存該int型成員,當該int型成員儲存完成後已經用了八個位元組的空間,因此此時double型成員的起始位置為第八號記憶體,滿足第一條條件,所以double型開始儲存,儲存完成後該結構體變數剛好佔16個位元組,剛好是最大資料型別double八個位元組的整數倍,所以儲存完成,因此該結構體變數佔了16個位元組。

再看這一題

 1 #include<stdio.h>
 2 
 3 typedef struct test
 4 {
 5      char a;
 6      double   b;
 7      int c;
 8 }TEST;
 9 
10 int main(void)
11 {
12      TEST test1;
13      printf("%ld\n",sizeof(test1));
14      
15      return 0;
16 }

這題乍一看和上一題的區別僅僅是將int型和double型調換了位置,那結果呢?結果肯定是不一樣的,按照上述分析步驟走一遍看看,先是char型從零號開始儲存,因為要遵循第一條原則故double型從八號開始儲存,一到七號被填充,double型儲存完後int型從16號位置開始儲存,儲存完成後發現此時一共佔了20個位元組的空間,不滿足第二條規則,因此又將20到23號位置填充,所以該結構體變數佔24個位元組,從這裡就可以看出在定義結構體時成員變數的順序會影響其在記憶體中所佔的資源大小,因此我們在定義結構體時要調整順序使其儘可能在記憶體中所佔空間最小。

其實記憶體對齊的規則和編譯環境也是有一定的關係,其預設對齊係數也有差異,並且也是可以通過預處理命令#pragma pack(n)來改變的。