改編自:
一,記憶體位址對齊的概念
計算機記憶體中排列、訪問資料的一種方式,包含基本資料對齊和結構體資料對齊。
32位系統中,資料匯流排寬度為32,每次能夠讀取4位元組資料。位址匯流排為32,最大定址空間為4gb。但是由於最低位a[0]~a[1]是不用於定址的,因此只能訪問4的倍數的位址空間,但是定址空間還是2^30*字長=4gb。
因此記憶體中除了結構體中成員變數之外的基本型別的開始的手位址最低兩位都是0。基本型別資料對齊就是資料在記憶體中的偏移位址必須是乙個字的倍數,以提高讀取資料時的效能。為了對齊資料,必須在上個資料結束和下個資料開始處插入一些位元組,這就是結構體資料對齊。
二,不進行對齊的影響
例如int a的位址是0x00fffff3,則其位元組分布在0x00fffff3~0x00fffff6空間內,為了讀取這個int,cpu必須對0x00fffff0和0x00fffff4進行兩次記憶體讀取,並處理得出的中間結果。兩次記憶體訪問將會浪費大量的時間,因為記憶體訪問的速度遠小於cpu處理指令的速度。
三,結構體的記憶體位址對齊
結構體本身必須是4位元組對齊的,而其成員變數則處理規則如下。
以下是microsoft和gnu對x86架構32位系統的結構體成員的預設對齊方式:
char 1位元組對齊
short 2位元組對齊
int 4位元組對齊
float 4位元組對齊
double windows是8位元組對齊,linux是4位元組對齊
當某乙個成員後邊的成員變數要求的位址對齊較大,則應該填入一些位元組。且總的結構體大小為最大對齊的倍數,因此最後可能還要填充一些字元。
因為上述結構體對齊的原因,將結構體成員按照大小遞增/遞減方式排序,可以減少結構體占用的空間大小。而這樣同時使得對整個結構體的訪問的效率變高了(占用小,整個的訪問次數可以降低)。
另外乙個提高效率的方法是把一些占用位元組數較少的成員合併到位元組數占用大的成員,形成union型別。比如,
struct merge{
int b;
union{
int a;
char b;
占用為8位元組。初始化需要3次記憶體讀,3次賦值,3次記憶體寫。
struct unmerge{
int b;
int a;
char b;
占用為12位元組。初始化需要2次記憶體讀,3次賦值,1次位移,2次記憶體寫。
但是用cpu的操作換取記憶體的讀寫可以很大的提高效能。基本上提高的效能比例等於記憶體訪問次數的較少數目和當前訪問次數的比例,此處為(6-4)/4=50%。
陣列或者結構體陣列只要保證首位址對齊,其中元素不要求對齊,因為對於陣列,其中任何元素都可以在1~2次記憶體訪問中獲取,對於結構體陣列,因為結構體內部是按照上述方式填充,則也不需要結構體陣列的元素都位址對齊。
對於效能要求較高的情況,比如tcp/ip協議的首部的定義,可以採用位段(bit-fields)的方式來對整數資料按照需要的字段數分配。當然,位段只能對整數進行操作,如果float和int型別資料放在一起用位段方式顯然不行,但是通過位移的方法也可以把char型別資料併入float或者double中。位段也需要遵循結構體對齊的方式。
四,使用者自定義
使用#pragma pack指令。
記憶體位址對齊
記憶體位址對齊,是一種在計算機記憶體中排列資料 訪問資料的一種方式,包含了兩種相互獨立又相互關聯的部分 基本資料對齊和結構體資料對齊。當今的計算機在計算機記憶體中讀寫資料時都是按字 word 大小塊來進行操作的 在32位系統中,資料匯流排寬度為32,每次能讀取4位元組,位址匯流排寬度為32,因此最大...
記憶體位址的對齊
3 有 pragma pack int 進行設定,如果結構體某成員的sizeof大於你設定的,則按你的設定來對齊 注意 每次用 pragma pack int 進行設定後,要用 pragma pack 對其結束,免得造成錯誤 view plain copy to clipboard print in...
自然對齊(記憶體位址)
c 中 基本資料型別的變數不能簡單的儲存於記憶體中的任意位址,他們的起始位址必須能被他們的大小整除。typedef unsigned char byte enum color struct eigth double m price color m color bool m isshift bool ...