私は以前にユニオンを快適に使用しました。今日、私はこの投稿を読んで、このコードが
union ARGB
{
uint32_t colour;
struct componentsTag
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} components;
} pixel;
pixel.colour = 0xff040201; // ARGB::colour is the active member from now on
// somewhere down the line, without any edit to pixel
if(pixel.components.a) // accessing the non-active member ARGB::components
実際には未定義の動作です。つまり、最近書き込まれたもの以外のユニオンのメンバーから読み取ると、未定義の動作になります。これがユニオンの使用目的ではない場合、何ですか?入念に説明してもらえますか?
更新:
後からいくつかのことを明確にしたいと思いました。
- 質問に対する答えは、CとC ++で同じではありません。私の無知な若い自己はそれをCとC ++の両方としてタグ付けしました。
- C ++ 11の標準を精査した後、非アクティブな共用体メンバーへのアクセス/検査が未定義/未指定/実装定義であると断言することはできませんでした。私が見つけたすべては§9.5/ 1でした:
標準レイアウト共用体に共通の初期シーケンスを共有する複数の標準レイアウト構造体が含まれ、この標準レイアウト共用体タイプのオブジェクトに標準レイアウト構造体の1つが含まれている場合、任意の共通初期シーケンスを検査することが許可されています標準レイアウトの構造体メンバーの。§9.2/ 19:対応するメンバーにレイアウト互換のタイプがあり、どちらのメンバーもビットフィールドではないか、1つ以上の初期シーケンスの幅が同じビットフィールドである場合、2つの標準レイアウト構造体は共通の初期シーケンスを共有しますメンバー。
- Cにいる間(C99 TC3-DR 283以降)、これを行うことは合法です(これをもたらしたPascal Cuoqに感謝します)。ただし、読み取った値が読み取られた型に対して無効である(いわゆる「トラップ表現」)場合、未定義の動作が発生する可能性があります。それ以外の場合、読み取られる値は実装定義です。
C89 / 90はこれを不特定の動作(Annex J)の下で呼びかけ、K&Rの本はその実装は定義されていると述べています。K&Rからの引用:
これが共用体の目的です-いくつかのタイプのいずれかを合法的に保持できる単一の変数。[...]使用法に一貫性がある限り:取得したタイプは、最後に保存されたタイプでなければなりません。ユニオンに現在格納されているタイプを追跡するのはプログラマの責任です。何かが1つのタイプとして格納され、別のタイプとして抽出される場合、結果は実装に依存します。
StroustrupのTC ++ PLからの抜粋(私の強調)
ユニオンの使用は、データの互換性のために不可欠です[...] 「型変換」に誤用されることがあります。
何よりも、この質問(私の質問以来、タイトルは変更されていません)は、共用体の目的を理解することを意図して提起されました。たとえば、コードの再利用のための継承の使用はもちろんC ++標準で許可されていますが、C ++言語の機能として継承を導入する目的や本来の意図ではありません。これが、アンドレイの答えが受け入れられたままである理由です。
scouring C++11's standard I couldn't conclusively say that it calls out accessing/inspecting a non-active union member is undefined [...] All I could find was §9.5/1
...本当に?段落の冒頭の主なポイントではなく、例外の注記を引用している場合:「ユニオンでは、非静的データメンバーの最大で1つがいつでもアクティブになることができます。つまり、非静的データメンバーはいつでもユニオンに格納できます。」-およびp4まで:「一般的に、明示的なデストラクタ呼び出しと配置演算子を使用して、ユニオンのアクティブなメンバーを変更する必要があります」
b, g, r,
且つa
連続でなくてもよいので、レイアウトが一致しませんuint32_t
。これは、他の人が指摘したエンディアネスの問題に追加されます。