これは常に「難しい」ものでした。他の人が指摘しているように、脚注は技術コレジェンダムを介してC99に追加されました。それは次のように読みます:
共用体オブジェクトのコンテンツにアクセスするために使用されるメンバーが、オブジェクトに値を格納するために最後に使用されるメンバーと同じでない場合、値のオブジェクト表現の適切な部分は、新しいタイプのオブジェクト表現として再解釈されます。 6.2.6で説明されています(「型のパンニング」と呼ばれることもあるプロセス)。これはトラップ表現である可能性があります。
ただし、脚注は序文で非規範的として指定されています。
付録DおよびFは、この標準の規範的な部分を形成します。付録A、B、C、E、G、H、I、J、参考文献、および索引は情報提供のみを目的としています。ISO / IEC指令のパート3に従い、この序文、序文、注記、脚注、および例も情報提供のみを目的としています。
つまり、脚注は行動を禁止することはできません。既存のテキストのみを明確にする必要があります。これは人気のない意見ですが、上で引用した脚注は実際にはこの点で失敗しています-規範的なテキストで禁止されているそのような行動はありません。実際、6.7.2.1などの矛盾するセクションがあります。
...最大で1つのメンバーの値は、いつでもユニオンオブジェクトに格納できます
6.5.2.3と組み合わせて(「。」演算子を使用したユニオンメンバーへのアクセスに関して):
値は指定されたメンバーの値です
つまり、1つのメンバーの値のみを格納できる場合、別のメンバーの値は存在しません。これは、ユニオンを介した型のパンニングが不可能であることを強く意味します。メンバーアクセスにより、存在しない値が生成されます。同じテキストがC11ドキュメントにまだ存在します。
ただし、脚注を追加する目的が型のパンニングを可能にすることであったことは明らかです。委員会が、規範的なテキストを含まない脚注の規則を破ったように見えるだけです。脚注を受け入れるには、脚注が規範的ではないというセクションを実際に無視するか、脚注の結論をサポートするような方法で規範的なテキストを解釈する方法を理解する必要があります(私が試しましたが、失敗しました)。
脚注を批准するために私たちができる最善のことは、6.2.5からの「重複するオブジェクト」のセットとしてのユニオンの定義についていくつかの仮定をすることです。
共用体型は、重複する空でないメンバーオブジェクトのセットを記述します。各オブジェクトには、オプションで指定された名前があり、場合によっては個別の型があります。
残念ながら、「オーバーラップ」が何を意味するのかについての詳細はありません。オブジェクトは、(3.14)「実行環境のデータストレージの領域。その内容は値を表すことができます」として定義されます(同じストレージ領域が2つ以上の別個のオブジェクトによって識別できることは、「重複するオブジェクト」によって示されます。 「上記の定義、つまり、オブジェクトはストレージ領域とは別のIDを持っています)。合理的な仮定は、(特定のユニオンインスタンスの)ユニオンメンバーが同じストレージ領域を使用することであるように思われます。
6.7.2.1 / 6.5.2.3を無視し、脚注が示すように、任意のユニオンメンバーを読み取ると、対応するストレージ領域のコンテンツによって表される値が返されることを許可したとしても、これにより型のパンニングが可能になります。 -6.5の問題のあるstrict-aliasingルールは、タイプ以外のオブジェクトへのアクセスを(特定のマイナーな例外を除いて)禁止します。「アクセス」は(3.1)「オブジェクトの値を読み取るまたは変更するための<実行時アクション>」であり、重複するオブジェクトのセットの1つを変更すると、必然的に他のオブジェクトも変更されるため、厳密なエイリアシングルールはユニオンメンバーに書き込むことによって違反される可能性があります(その後、別のメンバーを介して読み取られるかどうかに関係なく)。
たとえば、規格の文言では、次のことは違法です。
union {
int a;
float b;
} u;
u.a = 0; // modifies a float object by an lvalue of type int
int *pa = &u.a;
*pa = 1; // also modifies a float object, without union lvalue involved
(具体的には、コメント付きの2行は厳密なエイリアシングルールに違反しています)。
厳密に言えば、脚注は別の問題、つまり非アクティブな組合員を読むことについて語っています。ただし、上記の他のセクションと組み合わせた厳密なエイリアシングルールは、その適用性を大幅に制限し、特に、一般に型のパンニングを許可しないことを意味します(ただし、タイプの特定の組み合わせに対してのみ)。
苛立たしいことに、規格の開発を担当する委員会は、型のパンニングが一般に組合を通じて可能になることを意図しているようですが、規格のテキストがまだそれを許可していないことに問題はないようです。
注目に値するのは、(コンパイラベンダーによる)コンセンサスの理解は、共用体を介した型のパンニングが許可されているように見えることですが、「アクセスは共用体型を介して行う必要があります」(たとえば、上記の例の最初のコメント行であり、2番目の行ではない) )。これが読み取りアクセスと書き込みアクセスの両方に適用されるかどうかは少し不明確であり、標準のテキストではサポートされていません(脚注は無視してください)。
結論:共用体を介した型のパンニングは合法であると広く認められていますが(ほとんどの場合、アクセスが「共用体型を介して」行われる場合にのみ許可されると考えられます)、標準の文言は、特定の部分を除いてすべてを禁止しています。些細なケース。
あなたが引用するセクション:
共用体型のオブジェクトのメンバーに値が格納されている場合、そのメンバーに対応していないが他のメンバーに対応しているオブジェクト表現のバイトは、指定されていない値を取ります。
...ただし、注意深く読む必要があります。「そのメンバーに対応しないオブジェクト表現のバイト」は、メンバーのサイズを超えるバイトを参照しています。これは、型のパンニングの問題ではありません(ただし、ユニオンメンバーへの書き込みが大きなメンバーの「余分な」部分はそのままです)。