1. 程式人生 > 其它 >專案執行環境與專案經歷角色

專案執行環境與專案經歷角色

一、什麼是位元組對齊?

在現代計算機中,記憶體空間都是按照位元組(byte)劃分的。從理論上講對任何型別的變數的訪問可以從任何地址開始,但實際情況是,訪問特定型別的變數的時候經常在特定的記憶體地址訪問,這就需要各種型別的資料按照一定規則在空間上排列,而不是順序地一個接一個地排放,這種所謂的規則就是位元組對齊。這麼長一段話的意思是說:位元組對齊可以提升存取效率,也就是用空間換時間。

例如:

struct A
{
char a;
char reserved[3];//使用空間換時間
int b;
};

注:其中的reserved成員對於程式並沒有意義,只是起到了填補空間達到位元組對齊的目的。當然,即使不加這個成員,編譯器也會自動為我們補齊,加上它只是起到顯式提醒。

二、為什麼需要位元組對齊?

因為各個硬體平臺對儲存空間的處理上有很大的不同,一些平臺對某些特定型別的資料只能從某些特定地址開始存取。比如有些架構的CPU在訪問一個沒有進行對齊的變數的時候會發生錯誤,那麼在這種架構下程式設計必須保證位元組對齊.其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對資料存放進行對齊,會在存取效率上帶來損失。比如有些平臺每次讀都是從偶地址開始,如果一個int型(假設為32位系統)如果存放在偶地址開始的地方,那麼一個讀週期就可以讀出這32bit,而如果存放在奇地址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit資料。顯然在讀取效率上下降很多。

三、幾個基本概念

1、基本資料型別的自身對齊值

例如,char型資料的自身對齊值為1位元組,short型別自身對齊值為2位元組,int、float、long型別自身對齊值均為4位元組,double型別自身對齊值均為8位元組。(32位系統)

2、結構體或類的自身對齊值

其成員中自身對齊值最大的那個值。

3、指定對齊值

通過預編譯指令 #pragma pack (value) 來指定的對齊值value。(注:取消自定義對齊值得指令為 #pragma pack ( ))

4、資料成員、結構體和類的有效對齊值

其自身對齊值和指定對齊值中較小的那個值。

四、位元組對齊的幾個例子淺析

例1:設有如下兩個結構體

struct A
{
char a;
short b;
int c;
};
struct B
{
short b;
int c;
char a;
};
那麼上面兩個結構體的大小是多少呢?

對於結構體A:a是char型資料,佔用1位元組記憶體;short型資料,佔用2位元組記憶體;int型資料,佔用4位元組記憶體。因此,結構體A的自身對齊值為4,sizeof(struct A) =8位元組。

對於結構體B:同理也是4位元組對齊,但是sizeof(struct B) =12位元組。

例2:為結構體指定對齊值

#pragma pack(2) //指定2位元組對齊
struct C
{
char a;
int b;
short c;
};
#pragma pack() //取消指定對齊,恢復預設對齊
對於結構體C:由於其自身對齊值為4位元組(int b),而指定對齊值為2位元組,因此該結構體的有效對齊值為較小的2位元組,那麼sizeof(struct C) = 8 位元組。

#pragma pack(1) //指定1位元組對齊
struct D
{
char a;
int b;
short c;
};
#pragma pack() //取消指定對齊,恢復預設對齊
對於結構體D:同理可知,由於其自身對齊值為4位元組(int b),而指定對齊值為1位元組,因此該結構體的有效對齊值為較小的1位元組,那麼sizeof(struct D) = 7 位元組。

在預設情況下,C編譯器為每一個變數或是資料單元按其自然對界條件分配空間。一般地,可以通過下面的方法來改變預設的對界條件:

使用偽指令#pragma pack (n),C編譯器將按照n個位元組對齊。
使用偽指令#pragma pack (),取消自定義位元組對齊方式。
另外,還有如下的一種方式:

__attribute((aligned (n))),讓所作用的結構成員對齊在n位元組自然邊界上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
__attribute__ ((packed)),取消結構在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊。

五、總結

由以上分析可知,位元組對齊會造成空間上的浪費。 事實上,除了結構體之外,整個程式在給每個變數進行記憶體分配時都會遵循對齊機制,也都會產生記憶體空間的浪費。但我們要知道,這種浪費是值得的,因為它換來的是效率的提高。

參考部落格:https://blog.csdn.net/M_joy666/article/details/80030024