1. ホーム
  2. c++

[解決済み] ユニオンとタイプパンク

2023-01-03 06:58:42

質問

ずっと検索しているのですが、明確な答えが見つかりません。

多くの人が、ユニオンを使ってタイプパンをすることは未定義であり、悪い習慣だと言っています。これはなぜでしょうか。元の情報を書き込んだメモリが勝手に変更されないことを考えると、それが未定義の何かを行う理由は見当たりません (スタック上のスコープの外に出ない限り、それはユニオンの問題ではなく、設計の誤りでしょう)。

厳密なエイリアシングルールを引き合いに出す人がいますが、私にはそれができないからできないと言ってるようにしか思えません。

また、unionはpunをタイプしないなら何の意味があるのでしょうか?どこかで、異なる時間に異なる情報のために同じメモリ位置を使用することになっていると見ましたが、なぜ、再び使用する前に情報を削除しないのですか?

要約すると

  1. なぜ型の洒落にユニオンを使うのは良くないのか?
  2. もしそうでないなら、それは何のためでしょうか?

おまけ情報です。具体的には、CANバスで送信するために、浮動小数点と生の16進数の間の変換にユニオンを使用しています。

どのように解決するのですか?

繰り返しになりますが、共用体を介した型抜きは C では完全に問題ありません (ただし C++ では問題ありません)。対照的に、これを行うためにポインター キャストを使用すると、C99 の厳密なエイリアシングに違反し、異なる型が異なるアライメント要件を持つ可能性があり、間違った操作を行うと SIGBUS が発生する可能性があるため問題が発生します。ユニオンを使えば、これは決して問題ではありません。

C 標準からの関連する引用は以下の通りです。

C89 セクション 3.3.2.3 §5:

オブジェクトの別のメンバに値が格納された後に、ユニオンオブジェクトのメンバにアクセスした場合、その動作は実装で定義されます。

C11 6.5.2.3 §3:

.演算子と識別子が続くpostfix式は、structureまたはunionオブジェクトのメンバを指定します。値は指定されたメンバのものです。

を次の脚注95で指定します。

ユニオンオブジェクトの内容を読み取るために使われたメンバが、オブジェクトに値を格納するために最後に使われたメンバと同じでない場合、値のオブジェクト表現の適切な部分は 6.2.6 で述べたように新しい型でのオブジェクト表現として再解釈される(この処理は時に ''type punning'' と呼ばれる)。これはトラップ表現になるかもしれません。

これは完全に明確であるべきです。


James は、C11 セクション 6.7.2.1 §16 に次のような記述があるため、混乱しています。

メンバのうち最大1つの値は、いつでもユニオンオブジェクトに格納することができます。

これは矛盾しているように見えますが、そうではありません。C++とは対照的に、Cではアクティブなメンバーという概念はなく、互換性のない型の式を介して単一の格納された値にアクセスすることは全く問題ありません。

C11 annex J.1 §1 も参照してください。

最後に[are unspecified]に格納されたもの以外のユニオンメンバーに対応するバイトの値は指定されない。

C99では、これは

に格納された最後のもの以外のユニオンメンバーの値は不特定です]。

これは不正解でした。この附属書は規範的ではないため、独自のTCを評価せず、次の標準改訂まで修正されるのを待つ必要がありました。


標準 C++ に対する GNU 拡張 (および C90 に対する拡張) ユニオンを使った型抜きを明示的に許可する . GNU 拡張をサポートしていない他のコンパイラーでも、共用体の型抜きはサポートされているかもしれませんが、これは基本言語規格の一部ではありません。