web-dev-qa-db-ja.com

ユニオンによる型パンニングはC99で指定されていませんか?それはC11で指定されていますか?

スタックオーバーフローの質問に対するいくつかの回答 フロートのIEEE単精度ビットの取得 型パンニングにunion構造体を使用することを提案します(例:floatuint32_tに変換):

union {
    float f;
    uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;

ただし、ユニオンのuint32_tメンバーの値は、C99標準(少なくともドラフトn1124)に従って指定されていないようであり、セクション6.2.6.1.7に次のように記載されています。

Union型のオブジェクトのメンバーに値が格納されている場合、そのメンバーに対応しないが他のメンバーに対応するオブジェクト表現のバイトは、未指定の値を取ります。

C11 n1570ドラフトの少なくとも1つの脚注は、これがもはや当てはまらないことを示しているようです(6.5.2.3の脚注95を参照)。

共用体オブジェクトの内容を読み取るために使用されたメンバーが、オブジェクトに値を格納するために最後に使用されたメンバーと同じでない場合、値のオブジェクト表現の適切な部分は、新しい型のオブジェクト表現として再解釈されます。 6.2.6で説明されている(「タイプパニング」と呼ばれることもあるプロセス)。これはトラップの表現かもしれません。

ただし、セクション6.2.6.1.7へのテキストは、C11ドラフトと同じC99ドラフトでも同じです。

この動作は実際にはC99で規定されていませんか? C11で規定されていますか?ほとんどのコンパイラはこれをサポートしているようですが、それが標準で指定されているのか、それとも非常に一般的な拡張で指定されているのかを知っておくといいでしょう。

59
sfstewman

ユニオンを使用した型パンニングの動作がC89からC99に変更されました。 C99の動作はC11と同じです。

Wug が彼の回答で述べたように、タイプのパンニングはC99/C11で許可されています。ユニオンメンバーのサイズが異なる場合、トラップの可能性がある未指定の値が読み取られます。

脚注はClive D.Wの後にC99で追加されました。羽毛 欠陥レポート#257

最後に、C90からC99への変更の1つは、最後のストアが別のストアである場合に、ユニオンの1つのメンバーへのアクセスに関する制限を取り除くことでした。その理由は、動作が値の表現に依存するということでした。この点はしばしば誤解されているので、規格でそれを明確にする価値があるかもしれません。

[...]

「タイプパニング」に関する問題に対処するには、6.5.2.3#3の「名前付きメンバー」という単語に新しい脚注78aを添付します。78aユニオンオブジェクトのコンテンツへのアクセスに使用されるメンバーが最後のメンバーと同じでない場合オブジェクトに値を格納するために使用されます。値のオブジェクト表現の適切な部分は、6.2.6で説明されているように、新しいタイプのオブジェクト表現として再解釈されます(「タイプパニング」と呼ばれることもあります)。これはトラップの表現かもしれません。

クライヴD.W.の文言羽は技術委員会のC-委員会による 欠陥レポート#28 の回答で承認されました。

38
ouah

元のC99仕様では、これは指定されていません。

C99への技術的正誤表の1つ(TR2、私は思う)は、この見落としを修正するために脚注82を追加しました。

ユニオンオブジェクトのコンテンツにアクセスするために使用されるメンバーが、オブジェクトに値を格納するために最後に使用されたメンバーと同じでない場合、値のオブジェクト表現の適切な部分は、新しい型のオブジェクト表現として再解釈されます。 6.2.6で説明されている(「タイプパニング」と呼ばれることもあるプロセス)。これはトラップの表現かもしれません。

その脚注はC11標準に保持されます(C11の脚注95)。

17
Stephen Canon

これは常に「扱いにくい」ものでした。他の人が指摘したように、テクニカルコレジェンダムを介して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ドキュメントに存在しています。

ただし、脚注を追加する目的が型パンニングを可能にすることであったことは明らかです。委員会が規範的なテキストを含まない脚注のルールを破ったように見えるだけです。脚注を受け入れるには、脚注が規範的ではないというセクションを無視するか、または脚注の結論をサポートするような方法で規範的テキストを解釈する方法を理解する必要があります(私が試した、そして失敗しました)。

あなたが引用するセクション:

Union型のオブジェクトのメンバーに値が格納されている場合、そのメンバーに対応しないが他のメンバーに対応するオブジェクト表現のバイトは、未指定の値を取ります。

ただし、注意深く読む必要があります。 「そのメンバーに対応しないオブジェクト表現のバイト」は、メンバーのサイズを超えるバイトを参照していますが、それ自体はバイトではありませんタイプパニングの問題(ユニオンメンバーへの書き込みによって、より大きなメンバーの「余分な」部分がそのまま残るとは想定できない場合を除く)。

5
davmac