C語言中的數據對齊


數據對齊的目的,是用空間換時間,提高效率.

對齊本身並不難理解,但是有這么一個古怪的命令#pragma pack()存在,它可以人為指定按幾個字節來對齊.有了這個命令,就讓情況變得更加復雜了.

網上有很多#pragma pack()命令的使用方法總結,但我不認為這個命令是必要的,應該盡量避免使用.

如果你的代碼里使用了#pragma pack(),會導致sizeof()取得預料外的值,導致程序出錯.這個錯誤並不容易發現.

#pragma pack()能讓你的內存存儲變緊湊,但會讓sizeof()變得詭異,值得么?不值.

(也許寫程序傳輸協議時需要#pragma pack()來防止結構體中出現空洞?很牽強,我不認為這是必須的.)

干脆,拋開#pragma pack()命令,簡簡單單來理解數據對齊吧.

對齊表明了數據在內存中的存放方式,內存的最小單位是1字節,對齊長度為1說明數據可以存儲在任何內存地址.對齊長度為2說明只能存放在能被2整除的內存地址.對齊長度是4只能存放在能被4整除的內存地址.對齊長度只能是2的冪,也就是1,2,4,8,16...

數據對齊只會影響到結構體(或聯合),歸納起來有如下兩個規則:

1.結構體外的數據類型,它們按照自身大小來對齊.比如char型對齊長度是1,int型對齊長度是4,double型對齊長度是8.(32位系統下一般是這樣).

2.結構體本身也有一個對齊長度,這個值是內部成員中自身對齊長度最大的那個值.結構體需按自身對齊長度對齊,換句話說,結構體大小必須是本身對齊長度的整數倍.

根據上面兩條,你就會算結構體的大小了.

例1:

struct A
{
    char a;
    long b;
    char c;
    double d;
};

分析:

sizeof(struct A)=24.a占一個字節,b對齊長度是4,所以a后面補三個字節的洞后再存b.緊跟着是c占一個字節,d的對齊長度是8,所以c后面補7個字節的洞后再存d.共24字節.

struct A本身的對齊長度是8.

例2:

struct B
{
    char a;
    char b;
    long c;
    double d;
};

 分析:

sizeof(struct B)=16.a占一個字節,b也占一個字節.c對齊長度是4,所以b后補兩個字節洞后存c.d對齊長度是8,前面abc加起來恰好8字節,所以d可以緊跟c存放.共16字節.

struct B本身的對齊長度是8.

例3:

struct C
{
  char a[123];
  int b;
  float c;
  double d;
};

分析:

sizeof(struct C)=144.a占123個字節,后補一個字節洞后存4字節的b,此時地址仍然能被4整除,所以緊跟着存4字節的c,目前總長度132,補4字節洞后存入8字節的d.總大小144字節.

等等!有疑問!

char a[123]的對齊長度是1還是123?是1.數組並非一種數據類型,這個數組的數據類型是char,char的對齊長度是1.

所以,struct C的自身對齊長度是8,144是8的整數倍,沒問題.

例4:

struct D
{
  struct x
  {
    char a;
    int b;
    float c;
   }X;
  int d;
  char e;
};

分析:

sizeof(struct D)=20.先看struct x.a一個字節,補三個字節洞后跟4字節的b,之后是4字節的c.X的長度是12字節.struct x的自身對齊長度是4.再看struct D,X12字節,后跟4字節的d,之后是1個字節的e.struct D的自身對其長度是4(不是12,想一想吧).所以e后面要補三個字節洞.總長度是12+4+4=20.

例5:

struct E
{
  union y
  {
    char a;
    double b;
    int c;
  }Y;
  int d;
  double e;
};

分析:

sizeof(struct E)=24.Y是一個聯合,聯合的特點是它會占用跟最大的內部成員相同的空間,double最大,所以union y的對齊長度是8.之后是4字節的d.8+4=12為了對齊后面是8字節的e,d后面要補4字節的洞.所以總長度是8+8+8=24.

數據對齊基本就講完了,描述不是特別清楚,還請見諒.

在網上,看到有人提出了如下的疑問,請試試看能否替他解答一下呢?

Struct A
{
  char a,b;
  char arr[5];
}
//這個sizeof(A)=7.。1+1+5 = 7.。對齊單位為1字節。這個可以理解。

Struct B
{
  int a,b;
  char arr[5];
}
//這個sizeof(B) = 16.. 是怎么對齊的? 數組占了8個字節?。為什么?

 分析:

struct A自身的對齊長度是1,所以sizeof(struct A)=7這很容易理解.

struct B呢?自身的對齊長度是4,a+b+arr的長度是4+4+5=13,13不能被4整除(或者說13沒有按照自身對其長度對齊),所以要在最后補3個字節的洞變成16.

 

補充,如果考慮#pragma pack那么規則如下:

1)數據類型自身的對齊值:就是上面交代的基本數據類型的自身對齊值。

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

3)結構體或者類的自身對齊值:其成員中自身對齊值最大的那個值。

4)數據成員、結構體和類的有效對齊值:自身對齊值和指定對齊值中較小的那個值。

另外,在GCC中,#pragma pack的默認值是4,vc中默認值是8.這一點差別會帶來天差地別的不同,gcc里任何double類型都是按4字節對齊的.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM