字節對齊詳解--C++/C#版本


面試考察頻率:⭐⭐⭐⭐⭐

什么是字節對齊?

  計算機中內存都是按字節划分的,字節對齊就讓各類數據在按照特定的規則在內存中排列。如果一個數據在內存中的位置剛好是他自身長度的整數倍,則為字節對齊。

為什么要進行字節對齊?

為了可以解決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字節對齊那沒有什么關系,但效率可想而知~)。
所以得出結論,結構體內部字段順序,字節數越小的最好放在最上邊

基礎向的文章,歡迎大家一起學習討論。


免責聲明!

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



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