1. 程式人生 > >字節對齊

字節對齊

字節對齊



今天我們總結在C++和C語言中讓我們頭疼的字節對齊問題:


一、首先來看什麽是字節對其?

現代計算機中內存空間都是按照byte劃分的,從理論上講似乎對任何類型的變量的訪問可以從任

何地址開始,但實際情況是在訪問特定類型變量的時候經常在特定的內存地址訪問,這就需要各種類型數據按照一定的規則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。

二: 那麽問題就來了為什麽要字節對其?以及字節對其的作用?

各個硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。比如有些架構的CPU在訪問一個沒有進行對齊的變量的時候會發生錯誤,那麽在這種架構下編程必須保證字節對齊.其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對

數據存放進行對齊,會在存取效率上帶來損失。比如有些平臺每次讀都是從偶地址開始,如果一個int

型(假設為32位系統)如果存放在偶地址開始的地方,那麽一個讀周期就可以讀出這32bit,而如果存放在奇地址開始的地方,就需要2個讀周期,並對兩次讀出的結果的高低字節進行拼湊才能得到該32bit數

據。顯然在讀取效率上下降很多。


三、如何計算字節對齊

1、ok弄清了什麽是字節對其,以及字節對其的作用和影響,下來讓我們看字節是如何對其的:

首先這個字節對其與平臺有關,我們先用VC++6.0測試出Win32架構下各基本數據類型所占的字節:



技術分享



2、然後我們來看編譯器進行字節對其遵循的原則都是什麽?編譯進行字節對其時,遵循以下四個原則:


1.數據類型自身的對齊值:
對於char型數據,其自身對齊值為1,對於short型為2,對於int,float,double類型為4單位字節。其自身對齊值也就是上圖我求的基本數據類型的大小。

2.結構體或者類的自身對齊值:其成員中自身對齊值最大的那個值。
3.指定對齊值:#pragma pack (value)時的指定對齊值value。
4.數據成員、結構體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。


有了以上四個原則就可以判斷一個結構的大小。

最終用來決定數據存放地址方式的值,最重要。有效對齊N,就是表示“對齊在N上”,也就是說該數據的"存放起始地址%N=0".而數據結構中的數據變量都是按定義的先後順序來排放的。第一個數據變量的起始地址就是數

據結構的起始地址。結構體的成員變量要對齊排放,結構體本身也要根據自身的有效對齊值圓整(就是結構體成員變量占用總長度需要是對結構體有效對齊值的整數倍,結合下面例子理解)。這樣就不能理解上面的幾個例子的值了。

例子分析:
1、對於結構體只有基本數據類型以及構成的

struct Test1              //
{     char a;        //1
      int b;             //4   
      short c;
 };

下邊是測試結果:技術分享

對於這種情況我們來分析以下:

對於字節對其,我們始終要關註一個結構體的有效對齊值,編譯器默認對齊值一般是4個字節,有效值取結構體自身對齊值和指定對齊值的最小值,按照我的理解,我們在計算字節對其時,可以這樣計算:從第一個元素開始計算,a自身對齊值是1,系統默認對齊值是4,所以此時結構體自身對齊值是1,因而此時a不用補齊,到b時,b的自身對齊值是4字節,那麽此時結構體的自身對齊值是4字節,但是剛才的a又不是4的整數倍,因而又要退回去給a補三個字節,接著往下走,c的自身自身對齊值是2個字節,結構體的自身對齊值取結構體中的最大值,所以此時結構體的自身對齊值依然是4字節,4是2的整數倍,所以不用補齊,最後a,b,c總大小是10個字節不是4的倍數,最後再補兩個字節。所以結構體的大小是12個字節。

事實上,一個結構體出來以後,自身對齊值,也就出來了,自身對齊值,取結構體中數據成員最大值。然後再一一與結構體的成員比較對齊。最後根據有效對齊值,確定結構體的最終空間大小。

2、空結構體的大小

在標C中不允許出現空的結構體,C++中允出現空的結構體分配一個字節的空間

3、結構中有數組的情況

對於這種情況,還是按照上面分析的,先找出結構體的自身對齊值,然後補齊對齊。最後結構體的大小由結構體有效對齊值決定。

看測試案例:

技術分享

4、結構體中嵌套結構體

註意:這裏有一個細節需要註意如果結構體中嵌套的結構體沒有定義結構體變量的話不分配一個字節的大小,這相當於只是告訴編譯器有這麽一種類型,類型是不占 大小,只有分配變量後才有空間和大小。這種情況下,結構體的大小由其它成員決定。

技術分享

同樣的結構,我在內部結構體中加一個變量,結果就完全不一樣,

技術分享 對於這種結構,我們是按照先分析內部結構,計算出內部結構的大小,以及自身對齊值,然後按照一般的在計算外部結構的。具體分析這道題:

對於Test結構:系統默認的對齊值是四個字節,當到第一個元素ch時ch的自身對齊值是1,則此時結構體的自身對齊值是1,,所以此時ch不用補齊,然後d時,double的自身對齊值是8字節,那麽此時結構體的自身對齊值是8字節,d不用補齊,而ch需要補齊8字節,此時,ch補7個字節個字節,此時結構體一共16個字節,而最後結構體的大小還要看結構體有效對齊值,此時結構體自身對齊值是8,系統默認對齊值是4字節,16是4整數倍,所以內部結構體的最後大小就是16字節。此時Test與外部其他數據成員比較時,內部結構來說要看成一個數據類型,它的自身對齊值是8字節,但是內部結構體本身依然是開辟16字節的,對於外部結構體,自身對齊值取數據成員自身對齊值最大的,這裏也就是8字節。此時外部結構的空間大小一共24字節,而我們說過結構體最終空間的大小由有效值決定,此時外部結構體有效值是4字節,而24是4字節的整數倍所以結構體的最終大小是24字節。

編譯器一幫默認是4字節對齊,可以通過加命令調整默認對其方式,對於結構體來說,加了這條命令依然最後結構體的大小按照最後取小的計算,所以對於上面的情況只是多一個參考值。

4、聯合體空間大小

對於聯合體的大小取數據成員的最大值,但是聯合體最終大小還是由聯合體的自身對齊值決定,聯合體最後的大小必須是自身對齊值整數倍。註意這裏是自身對齊值,不是有效值。並且它不受pragma pack()的影響。

具體看下面代碼,也就是說,對於tes來說自身對齊值是8,聯合體的大小取最大的這裏也就是ch13和字節,但是它不是8的整數倍,所以補3個字節。

技術分享



以上就是我的理解,如果有不對的地方,歡迎各位指正。



本文出自 “12162969” 博客,請務必保留此出處http://12172969.blog.51cto.com/12162969/1955249

字節對齊