8

次の共用体のインスタンスの配列としてデータを格納するマルチスレッドアプリケーションがあります

union unMember {
    float fData;
    unsigned int uiData;
};

この配列を格納するオブジェクトは、ユニオン内のデータのタイプを認識しているため、正しいタイプを取得するときにUBに問題はありません。ただし、プログラムの他の部分では、これらのユニオンの2つのインスタンス間の同等性をテストする必要があり、コードのこの部分では、実際の内部データ型は不明です。この結果、この種のアプローチを使用して組合の平等をテストすることはできません。

  unMember un1;
  unMember un2;
  if (un1 == un2) {
     // do stuff
  }

コンパイラエラーが発生します。そういうものとして、私は単に組合のフロート部分を比較することです

  if (un1.fData == un2.fData) {
     // compiles but is it valid?
  }

UBが最後に書き込まれた部分ではないユニオンの任意の部分にアクセスしていることを読んだことを考えると(これは面倒に書かれていますが、これ以上明確な言い方は考えられません)、コードかどうか疑問に思っています上記は私のユニオンインスタンスの同等性をチェックする有効な方法ですか?

これにより、内部的には組合が実際にどのように機能しているかわからないことに気づきました。データは単純にビットパターンとして格納されており、ユニオンにリストされているタイプに応じて、好きなように解釈できると思いました。そうでない場合、ユニオンの2つのインスタンスの同等性をテストするための安全で正しい方法は何ですか?

最後に、私のアプリケーションはC ++で書かれていますが、ユニオンもCの一部であることに気付きました。それで、2つの言語での処理方法に違いはありますか?

4

5 に答える 5

9

一般に、現在の共用体タイプのある種のインジケーターを先頭に追加する必要があります。

struct myData
{
    int dataType;
    union {
        ...
    } u;
}

それで:

if (un1.dataType != un2.dataType)
    return (1 == 0);
switch(un1.dataType)
{
    case TYPE_1:
        return (un1.u.type1 == un2.u.type1);
    case TYPE_2:
        ...
}

とにかく、構文

if (un1.fData == un2.fData) {
    // compiles but is it valid?
}

これはコンパイルして有効ですが、2 つの理由で機能しない可能性があります。1つは、あなたが言ったように、un2には浮動小数点ではなく整数が含まれている可能性があるということです。しかし、その場合、通常、等価テストいずれにせよ失敗します。2 つ目は、両方の構造体が浮動小数点を保持し、わずかなマシン エラーで同じ数値を表していることです。次に、テストは、数値が異なる (少しずつ) ことを示しますが、それらの「意味」は同じです。

浮動小数点は通常次のように比較されます

if (dabs(f1 - f2) < error)

この落とし穴を避けるために。

于 2012-08-30T11:31:20.063 に答える
1

C++ では、最後に書き込まれたメンバーではないメンバーは初期化されていないと見なされます(そのため、それらの読み取りは未定義の動作です)。C では、それらは、有効なオブジェクト表現である場合もそうでない場合もある、書き込まれたメンバーのオブジェクト表現を含むと見なされます。

あれは、

union U {
    S x;
    T y;
} u;
u.x = 0;
T t = u.y;    // C++ - reading uninitialized memory - could crash
T t = u.y;    /* C - reading object representation of u.x - could crash */

実際には、割り当てられたメンバーを記述したコードからコードが十分に離れている場合、C++ での共用体の割り当てられていないメンバーの読み取りは、C と同じように動作します。・コンビネーションを書く。

両方の言語で安全な方法 (クラッシュしないことが保証されています) は、メモリの内容を次のような配列として比較することcharですmemcmp

union U u1, u2;
u1.x = 0;
u2.x = 0;

memcmp(&u1, &u2, sizeof(union U));

ただし、これは組合員の実際の平等を反映していない可能性があります。たとえば、浮動小数点型の場合、2 つNaNの値は同じメモリ表現を持ち、比較すると等しくない場合がありますが-0.00.0(負のゼロと正のゼロ) は異なるメモリ表現を持ちますが、比較すると等しくなります。また、2 つのタイプのサイズが異なる、または値に関与しないビットが含まれているという問題もあります (パディング ビット、ほとんどの最新のコモディティ プラットフォームでは問題になりません)。さらに、構造体型には位置合わせのためのパディングを含めることができます。

于 2012-08-30T11:42:13.810 に答える
0

一般的に、あなたが求めていることは不可能です。設定した変数からのメモリのみが、期待どおりであることが保証されます。他のメモリは基本的にランダムです。ただし、あなたの場合、すべてのサイズが同じであるため、比較できます。私がそれを行っていた場合、unsigned int を比較するか、memcmp を実行します。これはすべて、ユニオンのすべてのメンバーが同じサイズであるという事実に依存しています。たとえば、ダブルを追加すると、すべての賭けが無効になります。これは、C/C++ で行うことができるちょっとしたいじりに該当しますが、維持するのははるかに困難です。ユニオンについての仮定を行っており、この仮定を行ったことをコードで明確にする必要があります。将来のメンテナーはそれを吹き飛ばし、あらゆる種類のデバッグが難しい問題を引き起こす可能性があります.

最善の方法は、構造体に型フラグを設定するか、 Boost Variantなどを使用することです。このようなものを使用する場合、将来のメンテナーが知る機会がある、またはドキュメントを参照できる標準コードを使用して、将来の証明を行うことになります。

別の注意として、フロートの場合の等価性の意味を定義する必要があります。あいまいな比較が必要な場合は、確かに型を知る必要があります。ビットごとの比較が必要な場合は、それは簡単です。

于 2012-08-30T14:06:14.083 に答える
0

型が異なれば、記憶域の長さも異なる可能性があります (2 バイト対 4 バイト)。

共用体メンバーが書き込まれると、書き込まれたメンバーが正しいことが保証されるだけです。

次に、別のメンバーを比較すると、余分なバイトに何が入るかわかりません。

ユニオンの等価性をテストする正しい方法は、現在使用されているメンバーを示すユニオンとメンバーを含む構造体を持ち、そのメンバーをオンにすることです。たとえば、ユニオンとともに使用中の情報を保存する必要があります。

例えば

enum test_enum
{
  TEST_ENUM_INT,
  TEST_ENUM_FLOAT
};

union test_union
{
  int
    test_int;

  float
    test_float;
};

struct test_struct
{
  enum test_enum
    te;

  union test_union
    tu;
};
于 2012-08-30T11:29:28.323 に答える
0

代わりにクラスを実装した方が安全だと思います。コンストラクトが機能を提供しない場合 (この場合、評価する適切なメンバーが自動的に決定されます)、そのコンストラクトはニーズに合わない可能性があるため、別のコンストラクトを使用する必要があります;) それはカスタム クラス、またはおそらくVARIANTCOMを使用する場合(これは基本的に@lserniによって提案された構造体です)。

于 2012-08-30T12:03:02.627 に答える