まず、これは VLA ではなく、柔軟な配列メンバーです。VLA は、構造体のメンバーではなく、自動変数 (つまり、スタック上の通常の変数) のみにすることができます。これは、コンパイラが行う多くのことが、操作する要素のサイズを知ることに依存しているためです。
あなたのコメントに基づいて、ポインタには 4 バイトのアラインメント要件があり、16 ビット整数には 2 バイトのアラインメントが必要な 32 ビット プラットフォームを使用しているようです。そのため、sizeof は 64 バイトになります。sizeof の目的上、構造体に柔軟な配列メンバーがないように見えるため、今のところ無視できます。柔軟な配列メンバーは「偽の」メンバーであり、スペースを取りません。
コンパイラは、uint16_t の後に 2 バイトのパディングを追加して、dummy_struct の配列内でポインタが 32 ビット アラインメントを持つことを保証します。パディングがない場合、最初のポインターは uint16_t の直後に開始され、32 ビット境界に整列されません。
通常、コンパイラにパディングを行わないように強制することはできますが、これを行うための移植可能な方法はないことに注意してください。たとえば、gcc ではattribute ((packed))
、構造体で使用できます。これを行うと、sizeof(dummy_struct) は 62 バイトを返します。
B の場合、基本的にフレキシブル配列メンバーのオフセットを出力しています。C99 標準は次のように述べています。
特殊なケースとして、複数の名前付きメンバーを持つ構造体の最後の要素は、不完全な配列型を持つ場合があります。これは、柔軟な配列メンバーと呼ばれます。ほとんどの場合、柔軟な配列メンバーは無視されます。特に、構造体のサイズは、柔軟な配列メンバーが省略されている場合と同じですが、省略が意味するよりも多くの末尾のパディングがある場合があります。ただし、. (または ->) 演算子の左側のオペランドが柔軟な配列メンバーを持つ構造体 (へのポインター) であり、右側のオペランドがそのメンバーの名前である場合、そのメンバーが最長の配列 (同じ要素型を持つ) に置き換えられたかのように動作します。 ) アクセスされるオブジェクトよりも構造が大きくなることはありません。配列のオフセットは、置換配列のオフセットと異なる場合でも、柔軟な配列メンバーのオフセットのままです。
したがって、-> を使用すると、FAM は、sizeof によって報告されるサイズ (64 バイト) を変更せずに、最大サイズを持つ通常の配列のように動作します。この場合、サイズを変更せずに 1 つの 16 ビット整数のみを適合させることができます。この架空の構造体では、パディングはなく、1 つの要素の架空の配列のオフセットは 62 になります (uint16_t の直後)。これが、62 を取得する理由です。
FAM が int32_t の場合、サイズを変更せずに 0 要素を収めることができます (位置合わせを行うには 2 バイトのパディングが必要です)。標準では、これはサイズ 1 の配列のように動作すると言われています。そのため、FAM は sizeof が返すようにオフセット 64 になります。
繰り返します。単純に に変更int16_t array[]
するint array[]
と、A) は引き続き 64 を返しますが、B) は 62 ではなく 64 を返します。
これは、2番目の例でも発生します。FAM はポインターの配列になりました。あなたは 32 ビット プラットフォームを使用しており、構造体は 4 です。サイズを変更せずに FAM に 0 要素を収めることができます。したがって、そのオフセットは 4 です。