2016-05-15 18 views
2

sizeof()オペレータの行動を理解するのに役立つ人はいますか?クラスのサイズがメンバーの合計よりも大きいのはなぜですか?

#include <iostream> 

using namespace std; 

class A{ 
    int first; 
    double last; 
    public: 
    A(int a) 
    { 
     cout << a << endl; 
    } 
}; 
int main() 
{ 
    A a(3); 
    cout << sizeof(a) << endl; 
    return 0; 
} 

このコードは、16バイトのサイズを表示します。クラスのサイズはメンバーに基づいて計算されます。だから私は4バイト(int)+ 8バイト(double)= 12を持っています。

なぜ私は16バイトを得ましたか?

私がintdoubleのメンバーをコメントアウトすると、1バイトになります。

+0

は、Visual C++を使用する場合は、いいえ、私は普通のグラムを使用https://msdn.microsoft.com/en-us/library/xh3e3fd0.aspxを参照し、出力12 –

+0

を作るために '/ Zp1'オプションを試してみてください++コンパイラ –

+0

GCCはVisual C++と同じように「普通」です:)どんな場合でも、すべてのC++コンパイラは同様のオプションを提供します。このことは、本質的に実装固有のものです。 –

答えて

1

コンパイラはスピードやその他の要因のため、必ずしもを保存スペースのクラス内部をレイアウトするので、次の要素を取り付ける前に、サイズ-4要素の後ろに空の4バイトのブロックを残すかもしれません。これにより、現代のアーキテクチャ(64ビットベース= 8バイト)で次の要素へのアクセスが高速になります。

また、クラスオブジェクトのサイズには、仮想関数テーブルへのポインタなど、気づいていない他のデータが含まれている可能性があることに注意してください。コンパイラの仕事であり、コードが正しく高速に実行されます。

+0

コンパイラがクラスをレイアウトする方法が必ずしも速度のために最適化されているわけではないという点を除いて、ほとんど正しいです。他の要因もまた考慮に入れられる。特に、プラットフォームが他のコンパイラで使用されている準最適なABIを持っている場合、新しいコンパイラは、互換性を落とすことによってより速いABIを思い付いても、互換性のためにそのABIを使用することになります。 – hvd

+0

私は、仮想関数テーブルは、クラスの各インスタンスではなく、クラス全体のプロパティとして保存されると思います。 –

1

PODクラスがC構造体と互換性がある限り、クラス内のフィールドのレイアウトは実装定義です。しかし、Cの構造体の実装でさえ、パフォーマンスのようなさまざまな理由で埋め込みを追加します。したがって、コンパイラはdoubleフィールドを8バイトのアライメントされたアドレスから開始させるために、intフィールドの後ろに4バイトのパディングを追加する可能性があります。

特にこれが起こらないようにする必要がある場合は、コンパイラによって異なるクラス/構造体の整列と埋め込みを制御する方法があります。たとえば、GCCには、そのパディングを削除する__attribute__((packed))に似た構文があります。これはめったに必要ありません。ほとんどの場合、構造体がデバイスレジスタにマップする必要があり、通常はパフォーマンスを害するため、可能な場合は避けてください。

0

コンパイラがクラスにパックするデフォルトの方法は、単語の境界、つまり単語のサイズの倍数(64ビットマシンでは8バイト)に合わせることです。梱包を停止するには#pragma pack(1)またはコンパイラオプション/Zpを使用してください。これにより、コンパイラはメンバーを互いに強く押しつぶします。

クラスがゼロサイズを持つことは許されません。これは、2つの異なるオブジェクトへのポインタが同じであることを意味する可能性があるため、最小サイズは1バイトです。

+0

ええ、ありがとう。それは理にかなっている。 –

関連する問題