1. 程式人生 > >轉存下位元組對齊

轉存下位元組對齊

(1)什麼是位元組對齊

  一個變數佔用 個位元組,則該變數的起始地址必須能夠被 整除,即每個變數的起始存放地址 % n = 0, 
    對於結構體,這個 
取其成員種的資料型別佔空間的值最大的那個。

    即:A1儲存地址addr1%A1對齊值=0,A2按順序後延,如果下一個地址addr2%A2!=0就補空,後移儲存地址addr3。若addr3%A2!=0,繼續後移。
    同時,每個記憶體塊為最大的對齊值N,不滿的要補空。
    
    結構體中有結構體,把內中的結構體拆開看。 

  (2)為什麼要位元組對齊

  記憶體空間是按照位元組來劃分的,從理論上說對記憶體空間的訪問可以從任何地址開始,但是在實際上不同架構的CPU為了提高訪問記憶體的速度,就規定了對於某些型別的資料只能從特定的起始位置開始訪問。這樣就決定了各種資料型別只能按照相應的規則在記憶體空間中存放,而不能一個接一個的順序排列。

  舉個例子,比如有些平臺訪問記憶體地址都從偶數地址開始,對於一個int型(假設32位系統),如果從偶數地址開始的地方存放,這樣一個讀週期就可以讀出這個int資料,但是如果從奇數地址開始的地址存放,就需要兩個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到這個int資料,這樣明顯降低了讀取的效率。

  (3)如何進行位元組對齊

  每個成員按其型別的對齊引數(通常是這個型別的大小)和指定對齊引數(不指定則取預設值)中較小的一個對齊,並且結構的長度必須為所用過的所有對齊引數的整數倍,不夠就補空位元組。

  這個規則有點苦澀,可以把這個規則分解一下,前半句的意思先獲得對齊值後與指定對齊值進行比較,其中對齊值獲得方式如下:

  1. 資料型別的自身對齊值為:對於char型資料,其自身對齊值為1,對於short型為2,對於int, long, float型別,其自身對齊值為4,對於 double 型別其自身對齊值為8,單位為位元組。

  2.結構體自身對齊值:其成員中自身對齊值最大的那個值。

  其中指定對齊值獲得方式如下:

  #pragma pack (value)時的指定對齊值value。

  未指定則取預設值。

  後半句的意思是主要是針對於結構體的長度而言,對於結構體,它可能使用了多種資料型別,那麼這句話翻譯成對齊規則: 每個成員的起始地址 % 自身對齊值 = 0,如果不等於 0 則地址後移直到符合規則,前面的補空達到對齊值。

  換句話說,對於結構體而言,結構體在在記憶體的存放順序用如下規則即可映射出來:

  (一)單獨的每個成員的起始地址 % 每個成員的自身對齊值 = 0,如果不等於 0 就後移,前面補空使得每個成員記憶體塊為結構體中最大的對齊值。

  (二)結構體的長度必須為結構體的自身對齊值的整數倍,不夠就補空位元組。
舉例:
 typedef struct 
{
 char aa;
 short ab;
 char ac;
 long ad;
}A;
sizeof(A) 結果為: 12 記憶體位置為: $*$$  $***  $$$$ 注意:每個成員首地址必須為自身對齊值的整數倍。
 

typedef struct 
{
 long ba;
 short bb;
 long bc;
 char bd;
 short be;
}B;
sizeof(B)結果為:16  記憶體位置為:$$$$ $$** $$$$ $*$$   

typedef struct 
{
 char ca;
 char cb;
 short cc;
 char cd;
 short ce;
 A cf; 
 char cg;
 short ch;
 long ci;

}C;
sizeof(C)結果為:28  記憶體位置為:$$$$ $*$$ $*$$ $*** $$$$ $*$$ $$$$