C++中的字節對齊

(字節對齊的實現細節和編譯器有關)

1. 基本概念

字節對齊:計算機存儲系統中以Byte為單位存儲數據,不同數據類型所占的空間不同,如:整型(int)數據占4個字節,字符型(char)數據占一個字節,短整型(short)數據占兩個字節,等等。計算機為了快速的讀寫數據,默認情況下將數據存放在某個地址的起始位置,如:整型數據(int)默認存儲在地址能被4整除的起始位置,字符型數據(char)可以存放在任何地址位置(被1整除),短整型(short)數據存儲在地址能被2整除的起始位置。這就是默認字節對齊方式。

基本滿足以下3個原則:

  • 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除;
  • 結構體每個成員相對于結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節(internal padding);
  • 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之后加上填充字節(trailing padding)。

2. 舉例說明

很顯然默認對齊方式會浪費很多空間,例如如下結構:

struct student
{
    char name[5];
    int num;
    short score;
}

本來只用了11bytes(5+4+2)的空間,但是由于int型默認4字節對齊,存放在地址能被4整除的起始位置,即:如果name[5]從0開始存放,它占5bytes,而num則從第8(偏移量)個字節開始存放。所以sizeof(student)=16。于是中間空出幾個字節閑置著。但這樣便于計算機快速讀寫數據,是一種以空間換取時間的方式。其數據對齊如下圖:
|char|char|char|char|
|char|----|----|----|
|--------int--------|
|--short--|----|----|

如果我們將結構體中變量的順序改變為:

struct student
{
    int num;
    char name[5];
    short score;
}

則,num從0開始存放,而name從第4(偏移量)個字節開始存放,連續5個字節,score從第10(偏移量)開始存放,故sizeof(student)=12。其數據對齊如下圖:
|--------int--------|
|char|char|char|char|
|char|----|--short--|

如果我們將結構體中變量的順序再次改為為:

struct student
{
    int num;
    short score;
    char name[5];
}

則,sizeof(student)=12。其數據對齊如下圖:
|--------int--------|
|--short--|char|char|
|char|char|char|----|

3.#pragma pack()命令

為了節省空間,我們可以在編碼時通過#pragma pack()命令指定程序的對齊方式,括號中是對齊的字節數,若該命令括號中的內容為空,則為默認對齊方式。例如,對于上面第一個結構體,如果通過該命令手動設置對齊字節數如下:

#pragma pack(2) //設置2字節對齊
struct strdent
{
   char name[5]; //本身1字節對齊,比2字節對齊小,按1字節對齊
   int num;          //本身4字節對齊,比2字節對齊大,按2字節對齊
   short score;    //本身也2字節對齊,仍然按2字節對齊
}
#pragma pack() //取消設置的字節對齊方式

則,num從第6(偏移量)個字節開始存放,score從第10(偏移量)個字節開始存放,故sizeof(student)=12,其數據對齊如下圖:
|char|char|
|char|char|
|char|-----|
|----int----|
|----int----|
|--short---|

這樣改變默認的字節對齊方式可以更充分地利用存儲空間,但是這會降低計算機讀寫數據的速度,是一種以時間換取空間的方式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容