C 中的位元組對齊

2021-09-08 10:31:31 字數 4888 閱讀 6629

本部落格(

位元組對齊

1. 基本概念

位元組對齊:計算機儲存系統中以byte為單位儲存資料,不同資料型別所佔的空間不同,如:整型(int)資料佔4個位元組,字元型(char)資料佔乙個位元組,短整型(short)資料佔兩個位元組,等等。計算機為了高速的讀寫資料,預設情況下將資料存放在某個位址的起始位置,如:整型資料(int)預設儲存在位址能被4整除的起始位置,字元型資料(char)能夠存放在不論什麼位址位置(被1整除),短整型(short)資料儲存在位址能被2整除的起始位置。這就是預設位元組對齊方式。

2. 舉例說明

非常顯然預設對齊方式會浪費非常多空間,比如例如以下結構:

struct student

本來僅僅用了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

則,num從0開始存放,而name從第4(偏移量)個位元組開始存放,連續5個位元組,score從第10(偏移量)開始存放,故sizeof(student)=12。其資料對齊例如以下圖: 

|--------int--------|

|char|char|char|char|

|char|----|--short--| 

假設我們將結構體中變數的順序再次改為為:

struct student

則,sizeof(student)=12。其資料對齊例如以下圖: 

|--------int--------|

|--short--|char|char|

|char|char|char|----| 

驗證**例如以下:

#include typedef struct student1; typedef struct student2; typedef struct student3; int main() ; student2 s2=; student3 s3=; printf("student1 size = %d/n",sizeof(s1)); printf("student2 size = %d/n",sizeof(s2)); printf("student3 size = %d/n",sizeof(s3)); printf("/nstudent1 address : 0x%08x/n",&s1); printf(" name address : 0x%08x/n",s1.name); printf(" num address : 0x%08x/n",&s1.num); printf(" score address : 0x%08x/n",&s1.score); printf("/nstudent2 address : 0x%08x/n",&s2); printf(" num address : 0x%08x/n",&s2.num); printf(" name address : 0x%08x/n",s2.name); printf(" score address : 0x%08x/n",&s2.score); printf("/nstudent3 address : 0x%08x/n",&s3); printf(" num address : 0x%08x/n",&s3.num); printf(" score address : 0x%08x/n",&s3.score); printf(" name address : 0x%08x/n",s3.name); return 0; }

執行結果例如以下:

student1 size = 16 student2 size = 12 student3 size = 12 student1 address : 0x0013ff70 name address : 0x0013ff70 num address : 0x0013ff78 score address : 0x0013ff7c student2 address : 0x0013ff64 num address : 0x0013ff64 name address : 0x0013ff68 score address : 0x0013ff6e student3 address : 0x0013ff58 num address : 0x0013ff58 score address : 0x0013ff5c name address : 0x0013ff5e

3. #pragma pack()命令

為了節省空間,我們能夠在編碼時通過#pragma pack()命令指定程式的對齊方式,括號裡是對齊的位元組數,若該命令括號裡的內容為空,則為預設對齊方式。比如,對於上面第乙個結構體,假設通過該命令手動設定對齊位元組數例如以下:

#pragma pack(2) //設定2位元組對齊

struct strdent

#pragma pack() //取消設定的位元組對齊方式

則,num從第6(偏移量)個位元組開始存放,score從第10(偏移量)個位元組開始存放,故sizeof(student)=12,其資料對齊例如以下圖:

|char|char|

|char|char|

|char|-----|

|----int----|

|----int----|

|--short---|

這樣改變預設的位元組對齊方式能夠更充分地利用儲存空間,可是這會減少計算機讀寫資料的速度,是一種以時間換取空間的方式。

驗證**例如以下:

#include #pragma pack(2) typedef struct student1; typedef struct student2; typedef struct student3; #pragma pack() int main() ; student2 s2=; student3 s3=; printf("student1 size = %d/n",sizeof(s1)); printf("student2 size = %d/n",sizeof(s2)); printf("student3 size = %d/n",sizeof(s3)); printf("/nstudent1 address : 0x%08x/n",&s1); printf(" name address : 0x%08x/n",s1.name); printf(" num address : 0x%08x/n",&s1.num); printf(" score address : 0x%08x/n",&s1.score); printf("/nstudent2 address : 0x%08x/n",&s2); printf(" num address : 0x%08x/n",&s2.num); printf(" name address : 0x%08x/n",s2.name); printf(" score address : 0x%08x/n",&s2.score); printf("/nstudent3 address : 0x%08x/n",&s3); printf(" num address : 0x%08x/n",&s3.num); printf(" score address : 0x%08x/n",&s3.score); printf(" name address : 0x%08x/n",s3.name); return 0; }

執行結果例如以下:

student1 size = 12 student2 size = 12 student3 size = 12 student1 address : 0x0013ff74 name address : 0x0013ff74 num address : 0x0013ff7a score address : 0x0013ff7e student2 address : 0x0013ff68 num address : 0x0013ff68 name address : 0x0013ff6c score address : 0x0013ff72 student3 address : 0x0013ff5c num address : 0x0013ff5c score address : 0x0013ff60 name address : 0x0013ff62

若該為#pragma pack(1),則執行結果例如以下:

student1 size = 11 student2 size = 11 student3 size = 11 student1 address : 0x0013ff74 name address : 0x0013ff74 num address : 0x0013ff79 score address : 0x0013ff7d student2 address : 0x0013ff68 num address : 0x0013ff68 name address : 0x0013ff6c score address : 0x0013ff71 student3 address : 0x0013ff5c num address : 0x0013ff5c score address : 0x0013ff60 name address : 0x0013ff62

4. 樣例

程式例如以下:

#include class a1 ; class a2 ; class a3 ; class a4 ; class a5 ; main()

該樣例採取預設對齊方式,執行結果例如以下:

a1 size = 4 a2 size = 8 a3 size = 8 a4 size = 12 a5 size = 24

說明:靜態變數存放在全域性資料區內,而sizeof計算棧中分配的空間的大小,故不計算在內。

若加上#pragma pack(2)命令,則執行結果例如以下:

a1 size = 4 a2 size = 6 a3 size = 6 a4 size = 10 a5 size = 18

C 中位元組對齊以及位元組對齊的意義

對下面的類 class b 類b 物件的大小,如果直接計算是18 4 2 8 4 但是 sizeof b 結果是24。多出來的 6個位元組是怎麼回事呢?其實是記憶體對齊的原因。編譯器在預設的情況下,分配給各個成員變數的記憶體大小似乎是向佔最大空間的成員變數對齊的 這裡我不敢肯定,還沒看到權威的說法 ...

C 中的位元組對齊

一 位元組對齊的定義 計算機在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。二 對齊的作用和原因 1 平台原因 移植原因 不是所有的硬體平台都能訪問任意位址上的任意資料的 某些硬體平台只能在某些位址處取某些...

C 類中的位元組對齊

結果輸出如下 出人意料的,這兩行語句 cout sizeof p endl cout sizeof p.x sizeof p.y sizeof p.z endl 的輸出內容為 129 4 4 1 12 這是什麼原因?解釋這種原因的答案是 位元組對齊 乙個c 的類的物件或結構體中含有若干成員,其佔占用...