1. 程式人生 > >結構體位元組對齊筆記(Mac OS 10.9 中測試)

結構體位元組對齊筆記(Mac OS 10.9 中測試)

前言

    結構體位元組對齊相關的文章網路上有很多,看了其中幾篇寫的不錯的之後,做了一點總結,僅供自己日後回憶,請網友忽略。看過眾多關於位元組對齊的博文中,寫的我認為比較好的是實驗室蘇同學(ACM大神)寫的http://c4fun.cn/blog/2014/01/11/struct-alignment/,本文有部分內容摘自這篇部落格。另外Wiki上面的位元組對齊講的非常好,雖然是英文的。位元組對齊的目的很簡單,就是提高CPU讀取的效率。例如,32位機,CPU一次可以讀32位,那麼一個4位元組的資料的起始地址剛好在4的倍數上,那麼CPU一次就可以讀完,否則,CPU要讀取兩次。

記憶體對齊方法:

1、確定位元組對齊值

1)基本資料自身對齊值:基本資料型別的自身對齊值,一般由編譯器及系統決定;
2)結構體自身對齊值:取決於結構體成員中自身對齊值的最大值;
3)指定對齊值:通過#pragma pack(n)巨集指定的對齊值;
4)有效對齊值:取決於自身對齊值和指定對齊值中的較小值。

Wiki上32位系統的位元組對齊值。

  • char (one byte) will be 1-byte aligned.
  • short (two bytes) will be 2-byte aligned.
  • An int (four bytes) will be 4-byte aligned.
  • long (four bytes) will be 4-byte aligned.
  • float (four bytes) will be 4-byte aligned.
  • double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option).
  • long long (eight bytes) will be 8-byte aligned.
  • long double (ten bytes with C++Builder and DMC, eight bytes with Visual C++, twelve bytes with GCC) will be 8-byte aligned with C++Builder, 2-byte aligned with DMC, 8-byte aligned with Visual C++ and 4-byte aligned with GCC.
  • Any pointer (four bytes) will be 4-byte aligned. (e.g.: char*, int*)

The only notable difference in alignment for a 64-bit system when compared to a 32-bit system is:

  • long (eight bytes) will be 8-byte aligned.
  • double (eight bytes) will be 8-byte aligned.
  • long double (eight bytes with Visual C++, sixteen bytes with GCC) will be 8-byte aligned with Visual C++ and 16-byte aligned with GCC.
  • Any pointer (eight bytes) will be 8-byte aligned.

值得注意的是:

    如果用#pragma pack(n)指定對齊值的話,真正的位元組對齊值會取min(n,型別本身的對齊值)。

2.根據對齊值進行對齊

對齊方法遵循下面兩條規則,源自C4FUN博文。(有的博文上是4條規則,化簡了就是這兩條)

1)假設結構體的起始位置為0,結束位置為n,n+1必須是結構體有效對齊值的倍數。(如int型別,假設起始位置為0,結束位置為3,則n+1=4一定為有效對齊值的倍數)

2)假設某成員的起始對齊值是m,m必須是該成員有效對齊值的倍數。

實驗結果

我在Mac Os 10.9(64bit)系統下進行測試,clang+Xcode5編譯。程式碼如下:
#include <iostream>

typedef struct _C{
    int _int_32;
    char _char_8;
    int* _ptr_64;
    short _short_16;
}C;

typedef struct __C{
    int _int_32;
    char _char_8;
    short _short_16;
    int* _ptr_64;
}C_;

int main(int argc, const char * argv[])
{
    std::cout <<"sizeof int ="<<sizeof(int)<<std::endl;
    std::cout <<"sizeof char ="<<sizeof(char)<<std::endl;
    std::cout <<"sizeof int*(pointer) ="<<sizeof(int*)<<std::endl;
    std::cout <<"sizeof short ="<<sizeof(short)<<std::endl;
    std::cout <<"sizeof _C ="<<sizeof(C)<<std::endl;
    std::cout <<"sizeof __C ="<<sizeof(C_)<<std::endl;
    return 0;
}

命令列輸出:

sizeof int =4

sizeof char =1

sizeof int*(pointer) =8

sizeof short =2

sizeof _C =24

sizeof __C =16

    從輸出結果可以看出,第一個結構體的size為24位元組,第二個位16位元組。

分析結構體_C的記憶體佈局:


而結構體__C的記憶體佈局:


    結構體_C中為了為了滿足規則1,在地址5-7位置處填補了3個padding位元組。為了滿足規則2,在地址18-24處,填補了6個位元組的padding。而結構體__C中,將short的編排順序改變之後,剛好滿足了規則2。所以節省了8個位元組。可見,有效的利用變數編排順序,可以達到優化程式效能、縮小程式記憶體佔用的目的,以後寫結構體的時候不能隨意編排順序,應按照位元組對齊的規則,以最節省空間的方式編排。