5

質問1

私は次のような構造体を持っています、

struct foo
{
    int a;
    char c;
};

私が言うときsizeof(foo)、私は8自分のマシンに乗っています。私の理解では、int に 4 バイト、char に 1 バイト、パディングに 3 バイトです。あれは正しいですか?上記のような構造体が与えられた場合、パディングとして追加されるバイト数をどのように確認できますか?

質問2

sizeof配列のサイズを計算するために使用できることを認識しています。foosほとんどの場合、 ( is an array of foo)のような使用法を見てきました

sizeof(foos)/sizeof(*foos)

しかし、以下でも同じ結果が得られることがわかりました。

sizeof(foos) / sizeof(foo)

これら2つに違いはありますか?どちらが好ましいですか?

質問 3

次のステートメントを検討してください。

foo foos[] = {10,20,30};

するとsizeof(foos) / sizeof(*foos)、2になります。しかし、配列には3つの要素があります。ステートメントを次のように変更すると、

foo foos[] = {{10},{20},{30}};

正しい結果が得られます 3.なぜこれが起こっているのですか?

何かご意見は..

4

3 に答える 3

21

答え 1

はい - あなたの計算は正しいです。お使いのマシンではsizeof(int) == 4、 とintは 4 バイトでアラインされている必要があります。

基本要素のサイズを手動で追加し、sizeof() によって報告されたサイズからそれを差し引くことで、パディングについて調べることができます。マシンのアライメント要件がわかっている場合は、パディングを予測できます。一部のマシンは非常にうるさく、整列されていないデータにアクセスすると SIGBUS エラーが発生することに注意してください。より緩いものもありますが、位置合わせされていないデータにアクセスすると速度が低下します (また、' #pragma packed' などをサポートしている可能性があります)。多くの場合、基本型のサイズは 2 のべき乗 (1、2、4、8、16) であり、そのような n バイト型は n バイトで整列する必要があります。また、構造体の配列ですべての要素が適切に配置されるように、構造体をパディングする必要があることに注意してください。つまり、構造体は通常、構造体で最も厳密に整列されたメンバーのサイズの倍数までパディングされます。

答え 2

一般に、最初のバリアントの方が優れています。配列の基本型を「foo」から「foobar」に変更しても、正しいままです。私が通常使用するマクロは次のとおりです。

#define DIM(x) (sizeof(x)/sizeof(*(x)))

他の人は、同じ基本的な操作に対して別の名前を持っています。私が使用する名前は、ぼんやりとした遠い過去からの汚染と、BASIC の使用に基づいています。

いつものように、注意事項があります。malloc()最も顕著なのは、これを関数の配列引数または動的に割り当てられた配列 ( et al またはを使用) に意味のある方法で適用することはできませんnew[]。配列の実際の定義に適用しました。通常、値はコンパイル時の定数です。C99 では、配列が VLA (可変長配列) の場合、実行時に評価できます。

答え 3

十分なブレースがない場合の初期化の仕組みのためです。「foo」構造には 2 つの要素が必要です。10 と 20 は最初の行に割り当てられます。30 と暗黙の 0 が 2 番目の行に提供されます。したがって、サイズは 2 です。サブブレースを指定すると、配列には 3 つの要素があり、その最初のコンポーネントの値は 10、20、30 で、2 番目のコンポーネントはすべてゼロです。

于 2010-03-29T05:44:40.680 に答える
3
  1. パディングは通常、履歴 CPU のレジスタのサイズに関連しています。この場合、32 ビット CPU を使用しているため、int の「自然な」サイズは 4 バイトです。CPU がこのサイズより小さい量のメモリにアクセスするのは遅く、より困難であるため、通常は値を 4 バイト境界に揃えることをお勧めします。したがって、構造体のサイズは 4 バイトの倍数になります。ほとんどのコンパイラでは、使用するパディングの量を変更できますが (「#pragma」などを使用)、構造体のメモリ フットプリントが絶対的に重要な場合にのみ使用してください。

  2. 「*foos」は、foos 配列の最初のエントリを参照します。「foo」は型 (の単一インスタンス) を参照します。したがって、それらは本質的に同じです。*array は読み間違いやすいので、sizeof(type) または sizeof(array[0]) を自分で使用します。

  3. 最初の例では、配列エントリを正しく初期化していません。構造体には 2 つのメンバーがあるため、{ a, b } を使用して配列の各メンバーを初期化する必要があります。したがって、エントリを正しく初期化するには、{ {a, b}, {a, b}, {a, b} } という形式が必要です。

于 2010-03-29T05:48:28.563 に答える
2

パディングの量を調べるには、構造体の各要素の sizeof() を合計し、構造体全体の sizeof() からこの合計を差し引くだけです。

より複雑な構造体では、offsetof() を使用して、パディングがどこにあるかを正確に見つけることができます。これにより、要素を再配置して構造体全体のサイズを縮小することで穴を埋めることができます。

すべての要素が「自然に整列」することが保証されるように、パディング要素を手動で挿入して、構造要素を明示的に整列することをお勧めします。これらのパディング要素は、将来役立つデータに再利用できます。安定した ABI を必要とするライブラリを作成する場合、これは必須のテクニックです。

于 2010-03-29T06:29:48.220 に答える