VC++メモリ位置合わせ

6404 ワード

Aは構造体,クラス,または連合体であるsizeof(A)の値を求める問題をよく見る.
CPUのアクセスとメモリの最適化、メモリの断片化を減らすために、コンパイラはメモリの位置合わせにいくつかのルールを制定しました.しかし、異なるコンパイラには異なる実装がある可能性があり、本稿ではVC++コンパイラのみを対象とし、ここで使用するIDEはVS 2012である.
#pragma pack()は、メモリの位置合わせを表す前処理です.レイアウト制御#pragmaは、コンパイラに非常に規則的な制御フロー情報を提供する.
 
/**********構造体の大きさのルール*********/
構造体サイズは、プロセッサビット数と構造内の最長データ要素が占めるバイト数の両方の小さい整数倍です.
例えば、プロセッサビット数がnであり、構造内の最大データ要素が占めるバイト数がmであると仮定する.
プロセッサは32ビット、n=4です.構造体内の最大データ型はshort,m=2である.n > m;構造体の大きさはmの整数倍であり、逆も同様である.
注:64ビットのオペレーティングシステムの中には、コンパイラが32ビットであるものもある.
1 class A{
2   int a;
3   char b;
4   short c;
5 };

sizeof(A)は8で、4の整数倍です.
1 struct B{
2     short a;
3     short b;
4     short c;
5 };

sizeof(B)は6であり、2(sizeof(short))の整数倍である.
注意:C++の構造体はクラスと1つの違いしかありません.つまり、構造体メンバーのデフォルトはpublicであり、クラスのデフォルトはprivateです.
 
class X{
public:
    double a;
    float b;
    int c;
    char d;
};

sizeof(X)は20で,4(プロセッサビット数)の整数倍である.
 
/********* #pragma pack(n) *************/
#pragma pack(n)のnのデフォルトは4、すなわちプロセッサビット数32ですが、サイズは自分で定義できます.
#pragma pack(1)
class A{
public:
    int a;
    char b;
    short c;
};

このときsizeof(A)は7であり、1(#pragma pack(1))の整数倍となる.
#pragma pack(1)
    class X{
    public:
        double a;
        int b;
        short c;
        char d;
    };

sizeof(X)は15であり、1(#pragma pack(1))の整数倍である.
#pragma pack(4)
    class X{
    public:
        double a;
        int b;
        short c;
        char d;
    };

sizeof(X)は16であり、4(#pragma pack(4))の整数倍である.
#pragma pack(8)
    class X{
    public:
        double a;
        int b;
        short c;
        char d;
    };

sizeof(X)は16であり、8(#pragma pack(8)またはsizeof(double))の整数倍である.
 
/***********メモリ位置合わせ*************/
構造体内のデータ要素が存在するメモリアドレスは、2つの要因によって決定されます.
1つは#pragma pack(n)のn、2つは要素タイプが占めるバイト数、sizeof(type)であり、両者のうち小さい1つをとり、要素メモリアドレスから構造体またはクラスの開始アドレスへのオフセット量は小数の整数倍である.
例えば#pragma pack(n)のデフォルトは4で、以下の構造体があります.
struct A{
    int a;
    char b;
    short c;
};

aの開始アドレス距離構造体の開始アドレスのオフセット量は0でsizeof(int)の整数倍である.
bの開始アドレス距離構造体の開始アドレスのオフセット量は4であり、sizeof(char)の整数倍である.
cの開始アドレス距離構造体の開始アドレスのオフセット量は5であり、sizeof(short)の整数倍ではないので、その開始アドレスのオフセット量は5ではなく6になる.
出力a,b,cのアドレスは
0043FD68
0043FD6C
0043FD6E
cの先頭アドレスはbの先頭アドレスより2バイト大きく、bは2バイト分の大きさを占めていることがわかる.これはcのタイプがshort型で、大きさが2であるのに対し、nのデフォルトは4、sizeof(short)