4

私は次のタイプを持っています:

union {
  struct {
    uint32_t c0;
    uint32_t k0[4];
    uint32_t c1;
    uint32_t v[2];
    uint32_t i[2];
    uint32_t c2;
    uint32_t k1[4];
    uint32_t c3;
  } named;
  uint32_t array[16];
} state;

「named」内の各フィールドは初期化時に意味を持ちますが、その後は主に単語配列として使用します。Cは、、 isなどとstate.array[0]同じstate.named.c0であることを保証しますか?state.array[1]state.named.k0[0]

そうでない場合、それはどのくらい機能する可能性がありますか?コードに依存している場合にコードを壊すコンパイラ/プラットフォームはありますか?

4

3 に答える 3

3

あなたの最も気になる質問に答えるために、「..それが機能する可能性はどのくらいですか?」、それが確かなことでない限り、可能性に賭けないでください. この場合ではありません。

標準 (§6.7.2.1,p15) では、構造体の最初のメンバー、または共用体のすべてのメンバーのアドレスは、構造体または共用体自体のアドレスと同じであると規定されています。あなたにとって、これは と のアドレスが同一であることを意味するだけでarray[16]ありnamed、両方とも のアドレスと同等ですstate。ただし、実装依存のパッキングがなければ、構造体が正確にオーバーレイされるという保証はありません。これは、標準の同じセクションで、構造体間のパッキングが可能であると述べられているためです。

たとえば、何らかの理由で、常に 64 ビット境界でメンバーを開始するパッキング スキームを使用するコンパイラは、name次のようにレイアウトできます。

struct {
    uint32_t c0;
    **padding 4 bytes**
    uint32_t k0[4];
    uint32_t c1;
    **padding 4 bytes**
    uint32_t v[2];
    uint32_t i[2];
    uint32_t c2;
    **padding 4 bytes**
    uint32_t k1[4];
    uint32_t c3;
    **padding 4 bytes**
} name;

つまり、保証されているのname は、全体として占有されているメモリと、ユニオンの他のメンバーが占有しているメモリがarray[16]、それぞれのアドレス指定可能な場所の先頭から同じメモリを占有することだけです。のパッキングのカバーの下でそのメモリがどのように見えるかはname、実装と、提供したいパッキングのヒント次第です。

標準の関連部分の一部:

C99-§6.7.2.1,p6 6.2.5 で説明したように、構造体はメンバーのシーケンスから構成される型であり、その記憶域は順序付けられたシーケンスで割り当てられ、共用体は、記憶域がメンバーのシーケンスから構成される型です。重なります。

C99-§6.7.2.1,p15 構造体オブジェクト内で、非ビット フィールド メンバーとビット フィールドが存在するユニットには、宣言された順序で増加するアドレスがあります。適切に変換された構造体オブジェクトへのポインターは、その最初のメンバー (または、そのメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。構造体オブジェクト内に名前のないパディングがある場合がありますが、先頭にはありません。

C99-§6.7.2.1,p16 共用体のサイズは、最大のメンバーを含めるのに十分です。いつでも最大 1 つのメンバーの値をユニオン オブジェクトに格納できます。適切に変換された共用体オブジェクトへのポインターは、そのメンバーのそれぞれ (またはメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。

C99-§6.7.2.1,p17 構造体または共用体の末尾に名前のないパディングがある場合があります。

于 2013-01-22T03:56:43.940 に答える
2

C標準から:

6.7.2.1/15
構造体オブジェクト内で、非ビットフィールドメンバーとビットフィールドが存在するユニットには、宣言された順序で増加するアドレスがあります。適切に変換された構造体オブジェクトへのポインターは、その最初のメンバー(または、そのメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。構造体オブジェクト内に名前のないパディングがある場合がありますが、先頭にはありません。

6.7.2.1/16 共用体
のサイズは、最大のメンバーを含めるのに十分です。いつでも最大 1 つのメンバーの値をユニオン オブジェクトに格納できます。適切に変換された共用体オブジェクトへのポインターは、そのメンバーのそれぞれ(または、メンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。

鉱山を強調します。これは基本的に、同じアドレスを持つstate.namedstate.named.c0、およびに変換されます。state.arrayただし、ここにキャッチがあります。残りのnamedのメンバーがどこにあるかについての保証はありません (メモリ内の順序は指定されていますが、場所は指定されていません)。named技術的には、 の各メンバーの間にパディングが存在する可能性があります(また、 の最後にnamedも)。したがって、答えはノーです。それは保証されません。メンバーの間にパディングを追加できます。

重要なのは、最初の引用の最後の文です。

構造体オブジェクト内に名前のないパディングがある場合があります

于 2013-01-22T03:57:10.410 に答える
-3

はいstate.array[0]と同じstate.named.c0です。C は、「array[16]」と名前付き構造体が同じメモリ領域を占有することを保証します。

これは、データ型が一致している限り当てはまります。たとえば、2 つの並べ替えを保存してから整数を読み取る場合、結果はマシンに依存します。

于 2013-01-22T03:57:08.237 に答える