如何理解C++的內存對齊規則 探討結構體填充和alignas關鍵字

內存對齊是為了提高cpu訪問效率并滿足硬件要求。1. 數據類型需按自身大小對齊,如int按4字節對齊;2. 結構體成員起始地址必須是其類型對齊值的整數倍,否則插入填充字節;3. 結構體整體大小需為最大成員對齊值的整數倍;4. 成員順序影響填充量,合理排序可減少空間浪費;5. alignas關鍵字可顯式控制對齊方式,適用于底層優化場景。

如何理解C++的內存對齊規則 探討結構體填充和alignas關鍵字

理解c++的內存對齊規則,其實核心在于搞清楚兩個問題:為什么需要對齊怎么對齊。簡單來說,CPU在讀取內存時,訪問特定類型的數據如果落在它要求的對齊地址上,效率更高,甚至有些平臺強制要求必須對齊,否則會拋異常或者性能下降明顯。

如何理解C++的內存對齊規則 探討結構體填充和alignas關鍵字

所以結構體填充(padding)和alignas關鍵字,都是圍繞這個“對齊”機制來工作的。

如何理解C++的內存對齊規則 探討結構體填充和alignas關鍵字


結構體內存對齊的基本規則

結構體的大小不等于成員變量大小之和,這是因為編譯器會在適當的位置插入填充字節(padding),使得每個成員都滿足自己的對齊要求。

立即學習C++免費學習筆記(深入)”;

常見的對齊規則包括:

如何理解C++的內存對齊規則 探討結構體填充和alignas關鍵字

  • 每個成員的起始地址是其自身對齊值的整數倍
  • 結構體整體的大小是對齊值最大的那個成員的整數倍
  • 對齊值通常是類型的大小,比如int是4字節,則默認按4字節對齊;但也可以被修改

舉個例子:

struct Example {     char a;   // 1字節     int b;    // 4字節     short c;  // 2字節 };

假設在32位系統下,默認對齊方式為4字節:

  • a占1字節,放在0偏移處沒問題;
  • b要求從4的倍數開始,所以1~3是填充字節;
  • c要求從2的倍數開始,當前偏移是8(剛好符合),占用2字節;
  • 整體結構體大小要對齊到最大成員的對齊值(即4),所以最后可能還有2字節填充,總大小為12。

結構體填充是怎么發生的?

填充主要發生在兩個地方:

  • 成員之間:前面的成員不能滿足下一個成員的對齊要求時,中間插入填充
  • 結構體末尾:整個結構體的大小如果不是最大對齊值的整數倍,就補上填充

填充的目的不是浪費空間,而是為了訪問速度優化。例如,一個int如果被拆成兩次讀取,效率會大打折扣。

另外,結構體順序不同會導致填充也不同。比如把char放最后,結構體大小可能會變小:

struct Example2 {     int b;    // 4字節     short c;  // 2字節     char a;   // 1字節 };

此時填充量更少,結構體總大小可能是8而不是12。

所以設計結構體的時候,盡量按照對齊大小從大到小排列成員,可以減少填充,節省內存。


alignas關鍵字的作用與使用場景

C++11引入了alignas關鍵字,用于顯式指定某個變量或結構體的對齊方式。

它可以用來:

  • 強制某個變量以更大的對齊方式存儲
  • 控制結構體整體的對齊方式
  • 配合SIMD指令、內存池等底層操作

語法很簡單:

alignas(16) int x;  // x按16字節對齊  struct alignas(16) MyStruct {     int a;     double b; };

上面的例子中,即使MyStruct本身只需要8字節對齊,但由于用了alignas(16),整個結構體都會按16字節對齊。這對于某些需要嚴格對齊的場合非常有用,比如向量計算、DMA傳輸等。

需要注意的是:

  • alignas的參數必須是2的冪次
  • 如果多個alignas同時出現,會選擇最大的那個
  • 使用不當可能導致內存浪費,但能提升訪問效率

小結一下

內存對齊是C++中不可忽視的一個細節,特別是在做高性能或嵌入式開發時。結構體填充雖然看起來像“浪費”,但它是為了保證訪問效率和平臺兼容性。通過合理安排結構體成員順序、使用alignas關鍵字,可以更好地控制內存布局,避免不必要的空間浪費或性能損失。

基本上就這些。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享