7

この例を見てください

class A
{
public:
  int a; 
  char b;
  int c;
};

すべてのコンパイラ(x86、32、または64ビットの場合)はA、9ではなく12バイトをクラスに割り当てます。したがって、これらはb整数境界またはバス境界に整列しています。私の質問は、これがそうするためのC ++標準にあるかどうか、そしてそれをしないコンパイラがあるかどうかです。

4

5 に答える 5

17

C ++標準では、次のように指定されています。

  • オブジェクトには、サイズが倍数である配置要件があります(したがって、int幅が4バイトの場合、実装に応じて、1、2、または4バイトの配置が必要です)。
  • メンバーオブジェクト(などのアクセス指定子で区切られていない場合public)はすべて、宣言された順序で割り当てられます
  • そして、それらはそれらの位置合わせ要件を尊重して割り当てられます。

したがって、標準では、クラスのサイズを12バイトにする必要があると正確に規定されていません。

しかし、それはの後に割り当てられるべきであり、それはの後に割り当てられるべきであると言ってます。bacb

int幅が4バイトで、4バイトのアラインメントが必要なプラットフォームでは、これにより、有効な最小サイズとして12バイトが残ります。

  • a最初の4バイトを取ります
  • b1バイトかかります
  • c4バイト必要ですが、4バイト境界で割り当てる必要があります。bそのような境界を1バイト超えてc終了したため、 3バイトのパディングを挿入することにより、次に配置する有効な位置が見つかります。

したがって、クラスの合計サイズは、メンバーのサイズ(4 + 1 + 4 = 9)に3バイトのパディングを加えたものになり、合計で12になります。

a, c, bここでは効果がない別のルールがありますが、代わりに順序でメンバーを定義した場合は問題になります。

含まれているクラス(A)は、最も厳密に整列されたメンバーオブジェクトから整列要件を継承します。つまり、が含まれているためint、と同じ位置合わせ要件がintあります。a, b, cまた、オブジェクトの合計サイズは配置要件の倍数である必要があるため、メンバーを順番に含むクラスには12バイトのストレージが必要ですbとの間ではなく、3バイトのパディングをクラスの最後にシフトするだけcです。

ただし、場合によっては、メンバーをサイズの降順で並べ替えると、クラスのサイズが小さくなることがあります。

代わりに、次のようなクラスがあったとします。

class B {
  char a;
  double b;
  int c;
};

これには24バイトのストレージが必要でした(の場合は1バイト、のa場合は8バイト、のb場合は4バイトですcが、b最終的に8バイトの境界になるようにするには、との間に7バイトのパディングが必要です。クラス全体のサイズは8の倍数になり、の後にさらに4バイトが必要になります。abc

ただし、次のように、サイズに従ってメンバーを並べ替えます。

class B {
  double b;
  int c;
  char a;
};

その結果、クラスは16バイトしか必要としません。

メンバーオブジェクト自体に対して同じ1+4 + 8バイトですが、現在cはすでに4バイト境界で整列されており(その後bは8バイト境界で終了するため)、a整列は必要ないため、整列のみが行われます。必要なのはB、8の倍数のサイズであることを確認することです。メンバーは13バイトを使用するため、3バイトのパディングを追加でき、クラスは16バイトになり、最初のバージョンより33%小さくなります。

于 2012-11-08T14:07:55.437 に答える
1

プラグマディレクティブを使用して、コンパイル時に構造パッキングを制御することができます。 #PragmaPackを参照してください

たとえば、次の例では、メンバーを整列せず、メンバーを隣り合わせに配置します。

#pragma pack(push, 1)
struct A4
{
  char a;
  double b;
  char c;
};
#pragma pack(pop)

ここからの例。

GCCはプラグマパックもサポートしています。ディレクティブは一部の標準の一部ではありませんが、多くのコンパイラがそれをサポートしています。


ただし、上記を行う理由はありません。コンパイラーは、メンバーへのアクセスを高速化するためにそれらを調整します。これを変更する理由はありません

于 2012-11-08T14:05:18.020 に答える
0

あなたの場合、「b」は常に正しく整列されています。cを32ビット境界に揃えるためにパディングされます。特定の実装の余地はありますが、ほとんどのコンパイラーは、2バイトと4バイトの変数を2バイトと4バイトの境界に揃えるという規則に従います。

32ビットシステムでもdoublesとlongint(8バイト)は4バイト境界に揃えられますが、64ビットシステムでは8バイトに揃えられます。

于 2012-11-08T14:10:59.863 に答える
0

標準では、コンパイラは必要に応じてより多くのバイトをパディングできます。基本的には、コンパイラではなくホストのアーキテクチャに依存します。

于 2012-11-08T14:05:11.087 に答える
0

はい、アライメントは規格の至る所で言及されており、主にセクション3.11(アライメント)です。プラットフォームに依存するため、オブジェクトの実際のサイズに依存するプログラムは、本質的に移植性がありません。

于 2012-11-08T14:08:14.423 に答える