結構記憶體對齊
整形,浮點型和字符型乃至陣列都能計算大小,那么結構體的大小怎么計算呢?我們知道結構體成員都是由整形、浮點型字符型等組成的,那結構體大小是不是就是結構體成員大小相加,顯然沒有那么簡單,那么結構體大小到底是怎么計算大小的呢?
計算需要遵循結構體的對齊規則:
- 第一個成員在與結構體變數偏移量為0的地址處,
- 其他成員變數要對齊到某個數字(對齊數)的整數倍的地址處,
對齊數 = 編譯器默認的一個對齊數 與 該成員大小的較小值,
VS中默認的值為8 - 結構體總大小為最大對齊數(每個成員變數都有一個對齊數)的整數倍,
- 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍,
注意:默認對齊數不是所有編譯器都有,我這里是VS默認的對齊數是8,而linux下沒有默認對齊數,當沒有默認對齊數時,成員變數的大小就是該成員的對齊數,
結構體大小的計算
先拿結構體成員的大小和編譯器默認對齊數相比較,取較小的那一個為該成員變數的對齊數,我是VS默認對齊數是8

然后再把他們存進記憶體,存進去的時候就會發生記憶體對齊,存進去的時候每個成員變數都是存到自己的對齊數的整數倍的位置,

最后通過最大對齊數計算出結構體大小
從圖片可以看到紅色部分到藍色部分總大小為12個位元組,中間的白色則是被浪費掉的記憶體,這個結構體的大小為12,剛好是最大對齊數4的整數倍數,所以該結構體在VS的編譯器下大小就是12個位元組,所以創建這個結構體要在記憶體上開辟12個位元組的記憶體空間,
注意:大多數情況下,成員變數已經占用的總位元組個數并不一定是正好為其成員變數中的最大對齊數的整數倍數,這個時候則會發生記憶體對齊將記憶體擴大為最大對齊數的整數倍數,
為什么存在記憶體對齊?
- 平臺原因(移植原因): 不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址
處取某些特定型別的資料,否則拋出硬體例外, - 性能原因: 資料結構(尤其是堆疊)應該盡可能地在自然邊界上對齊, 原因在于,為了訪問未對齊的記憶體,處理器
需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問
總體來說:結構體的記憶體對齊是拿空間來換取時間的做法
設計結構體時的小技巧
我們在來看一個列子

對比上一個列子,相同的結構體成員這個占的記憶體為8而上個列子則為12,那么要怎么樣才能避免浪費掉過多的記憶體空間呢?
struct S1//占12個位元組
{
char c1;
int i;
char c2;
};
struct S2//占8個位元組
{
char c1;
char c2;
int i;
};
其實很簡單,我們只需要把占用記憶體小的成員盡量集中在一起,就可以有效的避免記憶體的浪費,
修改默認對齊數
要修改默認對齊數,則需要用到預處理命令
#pragma pack()
這個命令用法很簡單,只需要在括號里填上數字就可以修改默認對齊數,同樣的如果括號里面不填數字就會恢復為編譯器默認的對齊數,
看一下代碼
#include <stdio.h>
#pragma pack(1)//修改默認對齊數為1
struct s1
{
char i;
int c;
char b;
};
#pragma pack()//恢復默認對齊數
struct s2
{
char i;
int c;
char b;
};
int main()
{
printf("%d\n", sizeof(struct s1));
printf("%d\n", sizeof(struct s2));
return 0;
}

在結構體對齊方式不合適的時候我們可以修改默認對齊方式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/267439.html
標籤:其他
下一篇:2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final) 題解(AC:10 / 13)
