4
struct abc
{
  char arr[7];
  char arr1[2];
  int i:24;
};

sizeof 演算子を使用した上記の構造では、サイズが 12 バイトになりました。しかし、私の計算によると (間違っている可能性があります)、16 バイトである必要があります。なぜ12バイトを与えているのですか?

別の質問:

C99 セクション 6.7.2.1 パラグラフ 14 によると

構造体または共用体オブジェクトのビット ファイル化されていない各メンバーは、その型に適した実装定義の方法で整列されます。

特定の実装について、特定のコンパイラ (gcc など) が構造体にパディングを導入する方法を説明するドキュメントはどこで入手できますか? 特定のアーキテクチャのすべてのコンパイラに一般的なルールはありますか?

4

2 に答える 2

2

構造レイアウトは実装定義です。そして、たとえば GCC で使用されるデフォルトのレイアウトは、MSVC で使用されるレイアウトとは異なることが判明しました。MSVC がビットフィールドを含む構造体をレイアウトする方法に慣れていると思います。

ms_structもちろん、動作を変更できるGCC 属性があります。これについては、ドキュメントで詳しく説明されています。

したがって、この構造体のサイズは 16 です。

struct abc
{
  char arr[7];
  char arr1[2];
  int i:24;
} __attribute__((ms_struct));

デフォルトのオプションを使用するgcc_struct場合、サイズは 12 です。

特定の実装について、特定のコンパイラ (GCC など) が構造体にパディングを導入する方法を説明するドキュメントはどこで入手できますか?

各コンパイラのドキュメントを参照する必要があります。GCC の場合、ドキュメントには次のように記載されています。

4.9 構造体、共用体、列挙、およびビットフィールド

  • ユニオン オブジェクトのメンバーは、異なる型のメンバーを使用してアクセスされます (C90 6.3.2.3)。

    オブジェクトの表現の関連するバイトは、アクセスに使用されるタイプのオブジェクトとして扱われます。タイプパニングを参照してください。これはトラップ表現である可能性があります。

  • 「プレーンな」int ビットフィールドが signed int ビットフィールドとして扱われるか、unsigned int ビットフィールドとして扱われるか (C90 6.5.2、C90 6.5.2.1、C99 6.7.2、C99 6.7.2.1)。

    デフォルトでは、signed int として扱われますが、これは -funsigned-bitfields オプションで変更できます。

  • _Bool、signed int、および unsigned int (C99 6.7.2.1) 以外の許容されるビット フィールド型。

    厳密に適合するモードでは、他のタイプは許可されません。

  • ビット フィールドがストレージ ユニットの境界をまたぐことができるかどうか (C90 6.5.2.1、C99 6.7.2.1)。

    ABI によって決定されます。

  • ユニット内のビットフィールドの割り当て順序 (C90 6.5.2.1、C99 6.7.2.1)。

    ABI によって決定されます。

  • 構造体の非ビット フィールド メンバーのアラインメント (C90 6.5.2.1、C99 6.7.2.1)。

    ABI によって決定されます。

  • 各列挙型と互換性のある整数型 (C90 6.5.2.2、C99 6.7.2.2)。

    通常、列挙に負の値がない場合、型は unsigned int であり、それ以外の場合は int です。-fshort-enums が指定されている場合、負の値がある場合、すべての値を表すことができるのは、signed char、short、および int の最初のものであり、それ以外の場合は、すべてを表すことができる unsigned char、unsigned short、および unsigned int の最初のものです。その価値。

    一部のターゲットでは、-fshort-enums がデフォルトです。これは ABI によって決定されます。

したがって、概して、プラットフォームの ABI が何であるかを理解する必要があります。これは、どのコンパイラにとっても正気なことです。ABI に従って構造体をレイアウトしないと、相互運用が非常に難しくなります。

少し奇妙なのは、Windows での ABI とは何かに関する GCC の見解が、MSVC の実装とは異なることです。なぜそうなのかについての洞察はありません。

于 2013-04-14T11:24:18.300 に答える
1

とても簡単です。

struct abc
{
  char arr[7];  // occupies 7 bytes
  char arr1[2]; // occupies 2 bytes
  int i:24;     // occupies 3 bytes
};

さて、3 番目の宣言 (のi) では、3 バイトだけが必要です。次のようにすでにこれを持っています:

0 1 2 3 // All 4 bytes used for `char arr[7]`
0 1 2 3 // 3 more used for `char arr[7]`, 1 used for `char arr1[2]`
0 1 2 3 // 1 used for `char arr1[2]`, and the remaining 3 bytes will be used for `int i:24`

ただし、int i(ビットフィールドなし) を使用すると、16 バイトを消費します。

0 1 2 3 // All 4 bytes used for `char arr[7]`
0 1 2 3 // 3 more used for `char arr[7]`, 1 used for `char arr1[2]`
0 1 2 3 // 1 used for `char arr1[2]`, there are still 3 bytes but we need 4 bytes for an `int`
0 1 2 3 // So the compiler will allocate a new 4 byte chunk for `int i`

これでかなり明確になったと思います。

于 2013-04-14T11:14:28.120 に答える