面試考察頻率:⭐⭐⭐⭐⭐
什么是字節對齊?
計算機中內存都是按字節划分的,字節對齊就讓各類數據在按照特定的規則在內存中排列。如果一個數據在內存中的位置剛好是他自身長度的整數倍,則為字節對齊。
為什么要進行字節對齊?
為了可以解決CPU讀寫數據效率的問題
因為每個平台CPU所讀取的字節數是不同的,例如一個平台每次總是讀取4個字節,又有如下結構體:
struct Test
{
int a;
short b;
double c;
};
⚪如果不進行內存對齊(不對齊采用1字節對齊),該結構體在內存中排列方式如下圖所示(int 4字節,short 2字節,double 8字節):
這時候CPU取數據可能要執行兩次或多次內存訪問,降低效率。
⚪如果進行內存對齊(這里采用8字節對齊),該結構體在內存中排列方式如下圖所示:
這里我們就發現讀取數據可以很方便的每次從4的倍數字節開始的地方進行讀取,提升了讀取效率。
為了解決跨平台數據數據讀取問題
有的人開發時可能會遇到,明明在自己機器上可以正常運行讀取數據,但到了別的平台無法讀取各種奇怪的問題。這里就很有可能不同平台的CPU數據讀取方式不同,又加之沒有進行特定的字節對齊處理所導致的。所以一般跨平台可以使用1字節對齊,節省空間,但是效率過低。
如何實現字節對齊?
在c++中
主要通過 #pragma pack(n) 來實現
常用字節對齊指令如下:
指令 | 效果 |
---|---|
#pragma pack (n) | 作用:C編譯器將按照n個字節對齊。 |
#pragma pack () | 作用:取消自定義字節對齊方式。 |
#pragma pack (push,n) | 作用:是指把原來對齊方式設置壓棧,並設新的對齊方式,n不填就是不設置新的對齊方式 |
#pragma pack(pop) | 作用:恢復對齊狀態 |
還是上面的代碼,我們使用四字節對齊:
#pragma pack(4)
struct Test
{
int a;
short b;
double c;
};
運行結果為16。畫圖表示:
在c#中
主要通過 [StructLayout(LayoutKind.Sequential,CharSet =CharSet.Ansi,Pack =8)] 來實現。
還是上面的代碼,在C#中,也采用4字節對齊
[StructLayout(LayoutKind.Sequential,CharSet =CharSet.Ansi,Pack =4)]
struct Test
{
int a;
short b;
double c;
}
static void Main(string[] args)
{
int i = 1;
int size = Marshal.SizeOf(t);
Console.WriteLine(size);
}
和上面c++運行結果一樣,都為16。
講完了嗎,不還沒有,神奇的問題出現了。
還是剛才的代碼,順序稍微換一下,分別采用4字節和8字節對齊,可以猜猜看各自是多少。
//#pragma pack(4)
#pragma pack(8)
struct Test
{
int a;
double c;
short b;
};
結果為一個16字節(4字節對齊),一個24字節(8字節對齊)。
是的,結果體內部字段的排列順序會影響字節對齊所占空間大小。(當然如果都用1字節對齊那沒有什么關系,但效率可想而知~)。
所以得出結論,結構體內部字段順序,字節數越小的最好放在最上邊
基礎向的文章,歡迎大家一起學習討論。