學習筆記 | 字節對齊

目錄

01 什麼是字節對齊?
02 對齊準則又是什麼?
03 爲什麼要字節對齊呢?
04 字節對齊對我們編程有什麼啓示?

目的

  • 瞭解字節對齊,可以知道如何計算類/結構體的大小。

01 什麼是字節對齊?

  • 計算機中內存大小的基本單位是字節(byte),理論上來講,可以從任意地址訪問某種基本數據類型,但是實際上,計算機並非逐字節大小讀寫內存,而是以2,4,或8的倍數的字節塊來讀寫內存,如此一來就會對基本數據類型的合法地址作出一些限制,即它的地址必須是2,4或8的倍數。那麼就要求各種數據類型按照一定的規則在空間上排列,這就是對齊

02 對齊準則又是什麼?

  • 自對齊:是指該類型成員的其實位置的內存地址必須是自身長度的整數倍。如:int 類型只能以0、4、8…這類的地址開始。
  • 程序指定的對齊值:用命令#pragma pack時指定的對齊值。
  • 自定義類型的自身對齊:結構體或類的成員中自身對齊值是成員最大值。
  • 自定義類型的有效對齊值自定義類型的自身對齊和指定對齊值中取較小的值。
字節對齊有以下準則:
  • 結構體變量的首地址能夠被其對齊字節數大小所整除。
  • 結構體每個成員相對結構體首地址的偏移都是成員大小的整數倍,如不滿足,對前一個成員填充字節以滿足。
  • 結構體的總大小爲結構體對齊字節數大小的整數倍,如不滿足,最後填充字節以滿足。
struct MyStruct
{
  char dda; //偏移量爲0,滿足對齊方式,dda佔用1個字節;
  double dda1;//下一個可用的地址的偏移量爲1,不是sizeof(double)=8的倍數,需要補足7個字節才能使偏移量變爲8(滿足對齊方式),因此VC自動填充7個字節,dda1存放在偏移量爲8的地址上,它佔用8個字節。
  int type; //下一個可用的地址的偏移量爲16,是sizeof(int)=4的倍數,滿足int的對齊方式,所以不需要VC自動填充,type存放在偏移量爲16的地址上,它佔用4個字節。
}//所有成員變量都分配了空間,空間總的大小爲1+7+8+4=20,不是結構的節邊界數(即結構中佔用最大空間的類型所佔用的字節數sizeof(double)=8)的倍數,所以需要填充4個字節,以滿足結構的大小爲sizeof(double)=8的倍數。所以該結構總的大小爲:sizeof(MyStruc)爲1+7+8+4+4=24。其中總的有7+4=11個字節是VC自動填充的,沒有放任何有意義的東西。

在這裏插入圖片描述

03 爲什麼要字節對齊呢?

  • 無論數據是否對齊,大多數計算機還是能夠正確工作。
那麼爲什麼還要進行字節對齊呢?最重要的考慮是提高內存系統性能。
  • 需要字節對齊的根本原因在於CPU訪問數據的效率問題

  • 前面我們也說到,計算機每次讀寫一個字節塊,例如,假設計算機總是從內存中取8個字節,如果一個double數據的地址對齊成8的倍數,那麼一個內存操作就可以讀或者寫,但是如果這個double數據的地址沒有對齊,數據就可能被放在兩個8字節塊中,那麼我們可能需要執行兩次內存訪問,才能讀寫完成。顯然在這樣的情況下,是低效的。所以需要字節對齊來提高內存系統性能。

跨平臺通信

  • 由於不同平臺對齊方式可能不同,如此一來,同樣的結構在不同的平臺其大小可能不同,在無意識的情況下,互相發送的數據可能出現錯亂,甚至引發嚴重的問題。因此,爲了不同處理器之間能夠正確的處理消息,我們有兩種可選的處理方法。
  1. 1字節對齊
  2. 自己對結構進行字節填充
  • 我們可以使用僞指令#pragma pack(n)n爲字節對齊數)來使得結構間一字節對齊。

04 字節對齊對我們編程有什麼啓示?

  • 雖然我們不需要具體關心字節對齊的細節,但是如果不關注字節對齊的問題,可能會在編程中遇到難以理解或解決的問題。
因此針對字節對齊,總結了以下處理建議:
  • 結構體成員合理安排位置,以節省空間。
  • 跨平臺數據結構可考慮1字節對齊,節省空間但影響訪問效率。效率之所以降低,是因爲:如果存在更大字節數的變量時(比1大),比如int類型,需要進行多次讀週期才能將一個int數據拼湊起來。
  • 跨平臺數據結構人爲進行字節填充,提高訪問效率但不節省空間。
  • 本地數據採用默認對齊,以提高訪問效率。

在這裏插入圖片描述

舉例

#include <iostream>
#include <stdio.h>
using namespace std;
int main(){
 
    struct A{
        char a;
        short b;
        int c;
    };
 
    cout << "size of struct A = " << sizeof(struct A) << endl;;

 
    struct B{
        short b;
        int c;
        char a;
    };
    cout << "size of struct B = " << sizeof(struct B) << endl;;
 
}

輸出:
在這裏插入圖片描述

struct A

在這裏插入圖片描述

struct B

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章