關於struct結構體填充造成的位元組數的問題

2021-06-29 07:01:21 字數 4097 閱讀 8307

有如下的結構體的定義:

struct aa;
問題, 求對struct進行sizeof的時候, 得到的大小數。

問題解析: 當記憶體中的值合理對其的時候, 很多機器能夠高效的訪問。 例如, 按位元組定址的32位機器中, 有兩個位元組的short型變數必須放在偶數字址上, 而4位元組的int型變數, 必須放在4的整數倍位址上。 某些機器甚至根本不能訪問沒有對齊的位址。 所以必須要求所有的資料正確的對齊。 

為了解決上述問題, 我們要知道, 32位機器, 對於指標變數, 無論是char型還是int型, 指標變數存的都是位址, 都占用4bytes。

下面我們一步一步分析:

struct aa;
上述在記憶體中占用1個byte。 |

struct aa;
上述本來佔據5個byte。 但是由於要求int型變數b的位址必須是4的倍數, 所以占用1(for char) + 3 (填充用的) + 4(for int), 故而占用8個bytes。

| - - -| | | |

truct aa;

上述占用了12個位元組。 因為已經滿足4的倍數啦。

| - - -  | | | |   | | | | 

struct aa;
上述占用12 + 8個位元組。 但是double要求位址offset從8的整數倍開始, 所以填充4個位元組, 變成16, 變成8的倍數, 在存下double。 是 12 + 4  + 8 = 24 bytes:

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | |

下面:

struct aa;
上述占用24 + 8 = 32bytes。雖然要char*pa 變數占用4bytes, 但是 因為要按照double的對其格式。

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  - - - - 

struct aa;
上述占用仍然是32 bytes, 因為最後已經有四個空著的bytes, 仍然滿足位址是8的倍數。

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  (int*) | | | |

struct aa;

上述占用時32 + 8 = 40 bytes, 因為 short要按照double的格式對其, 即總的位址要是8的倍數。 

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  (int*) | | | | (short) | | - -  - - - -

也就是最後尾部還剩下6個bytes空著了。 試想

struct aa;

由於空6個bytes, 必須是4的倍數, 所把最後四個給占用了。 所以當然還是40bytes。 當然是。

(char)| - - - (int) | | | |  (float)| | | | - - - -   (double)| | | | | | | | (char*) | | | |  (int*) | | | | (short) | | - -  (int) | | | |

接下來, 如果再加乙個short, 就變成了48了, 當然是啦:

struct aa;
編譯器可能提供用於控制結構體的這種填充。 例如#pragma, 這樣我們就可以遮蔽掉變數的對齊方式, 自己設定變數的對齊方式。 

例如編譯器提供#pragma pack(n) 來設定變數以n位元組對齊的方式。 n 位元組的對齊方式指的是, 如果n 大於該變數所佔的位元組數, 那麼偏移量必須滿足預設的對齊方式, 如果n 小於變數型別所佔的位元組數, 那麼偏移量必須為n的倍數。 

舉例子如下:

#include using namespace std;

#pragma pack(push) // 保持對齊方式

#pragma pack(4) // 設定4位元組對齊

struct aa;

#pragma pack(pop) // 恢復對齊方式

int main()

執行結果如下:

分析如下:

4 + 4 + 4 + 8 + 4 + 4 + 4 = 32.

如果我們設定1位元組對齊:

#include using namespace std;

#pragma pack(push) // 保持對齊方式

#pragma pack(1) // 設定1位元組對齊

struct aa;

#pragma pack(pop) // 恢復對齊方式

int main()

執行結果為:

分析:

1 + 4 + 4 + 8 + 4 + 4 + 2 = 27. 

okay。 完美解決。 

為了理解pack, 給出如下例子:

#include using namespace std;

#pragma pack(push, 1) // 可以合併在一起寫

struct name;

#pragma pack(pop)

int main()

執行:

執行:

改為:

#include using namespace std;

#pragma pack(push, 8)

struct name;

#pragma pack(pop)

int main()

執行

再比如下面:

#include using namespace std;

#pragma pack(8)

struct aa ;

#pragma pack()

int main()

佔8個位元組:

再比如:

#pragma pack(8)

struct aa ;

#pragma pack()

仍佔8個位元組。

在比如:

#pragma pack(8)

struct aa ;

#pragma pack()

上述佔12個位元組。 按照預設的對齊方式。

關於結構體struct 1

自2010年9月學習c語言到現在,已超過3年時間了。期間陸陸續續用它寫過一些學生 c語言雖然看起簡單,實際上花費了幾年時間,對它的了解依舊不多,不能說熟悉掌握。今天就從結構體說起。0.什麼是結構體型別 struct type 稍微有看過c入門的同學都知道,所謂結構體型別,即結構體體 struct b...

複習關於C的結構體struct

今天見到乙個結構體函式指標,有些迷糊,在自己複習和整理一下c的結構體 struct 知識。其中大部分內容 於網路。基本定義 結構體,通俗講就像是打包封裝,把一些有共同特徵的變數封裝在內部,通過一定方法訪問修改內部變數。說明和使用之前必須先定義它,也就是構造它。如同在說明和呼叫函式之前要先定義一樣。結...

什麼結構體 struct

簡單的來說,結構體就是乙個可以包含不同資料型別的乙個結構,它是一種可以自己定義的資料型別,它的特點和陣列主要有兩點不同,首先結構體可以在乙個結構中宣告不同的資料型別,第二相同結構的結構體變數是可以相互賦值的,而陣列是做不到的,因為陣列是單一資料型別的資料集合,它本身不是資料型別 而結構體是 陣列名稱...