質問

標準 C では、構造体の 2 つのインスタンスが等しいかどうかをどのように比較しますか?

役に立ちましたか?

解決

Cはこれを行うための言語機能を提供していません-自分でそれを行い、メンバーごとに各構造を比較する必要があります。

他のヒント

memcmp(& a、& b、sizeof(struct foo))を使用したくなるかもしれませんが、すべての状況で機能するとは限りません。コンパイラーは構造体にアライメントバッファースペースを追加できますが、バッファースペース内のメモリ位置で見つかった値は特定の値であるとは限りません。

しかし、使用する前に構造のフルサイズを calloc または memset を使用すると、浅いことができます memcmp との比較(構造体にポインターが含まれている場合、ポインターが指しているアドレスが同じ場合にのみ一致します)。

多くの場合、2つの構造を比較する関数を作成することをお勧めします。そうすれば、構造を変更した場合でも、比較を1か所で変更するだけで済みます。

その方法については...すべての要素を個別に比較する必要があります

memcmpを使用して、構造体のフィールド間でランダムなパディング文字が発生する可能性があるため、構造体の等価性を比較することはできません。

  // bad
  memcmp(&struct1, &struct2, sizeof(struct1));

次のような構造体では、上記は失敗します。

typedef struct Foo {
  char a;
  /* padding */
  double d;
  /* padding */
  char e;
  /* padding */
  int f;
} Foo ;

安全にするには、メンバーごとの比較を使用する必要があります。

非静的構造でmemcmp()を使用できることに注意してください 初期化しない限り、パディングを心配する すべてのメンバー(一度に)。これはC90で定義されています:

http://www.pixelbeat.org/programming/gcc/auto_init.html

@Gregは、一般的な場合に明示的な比較関数を作成する必要があることは正しいです。

memcmp は次の場合に使用できます。

  • 構造体には、 NaN である可能性のある浮動小数点フィールドが含まれていません。
  • 構造体にパディングが含まれていない(これを確認するにはclangで -Wpadded を使用)または初期化時に構造体が memset で明示的に初期化されます。
  • 異なるが同等の値を持つメンバータイプ(Windows BOOL など)はありません。

組み込みシステム用のプログラミング(またはそれらで使用される可能性のあるライブラリの作成)をしている場合を除き、C標準のコーナーケースの一部については心配しません。 32ビットまたは64ビットのデバイスには、ニアポインターとファーポインターの区別はありません。私が知っている非組み込みシステムには、複数の NULL ポインターがありません。

別のオプションは、等式関数を自動生成することです。構造体定義を簡単な方法でレイアウトすると、単純なテキスト処理を使用して単純な構造体定義を処理できます。一般的な場合にlibclangを使用できます– Clangと同じフロントエンドを使用するため、すべてのコーナーケースを正しく処理します(バグがない場合)。

このようなコード生成ライブラリは見たことがありません。ただし、比較的単純に見えます。

ただし、このように生成された等式関数は、アプリケーションレベルで間違った動作をすることがよくあります。たとえば、Windowsの2つの UNICODE_STRING 構造体を浅くまたは深く比較する必要がありますか

あなたが尋ねている質問が以下であるかどうかによります:

  1. これら2つの構造体は同じオブジェクトですか?
  2. 同じ値ですか?

それらが同じオブジェクトであるかどうかを調べるには、2つの構造体へのポインターが等しいかどうかを比較します。 それらが同じ値を持っているかどうかを一般的に調べたい場合は、詳細な比較を行う必要があります。これには、すべてのメンバーの比較が含まれます。メンバーが他の構造体へのポインタである場合、それらの構造体にも再帰する必要があります。

構造体にポインターが含まれない特別な場合、memcmpを実行して、データの意味を知らなくても、それぞれに含まれるデータのビットごとの比較を実行できます。

各メンバーの「等しい」の意味を必ず確認してください-intには明らかですが、浮動小数点値またはユーザー定義型に関してはより微妙です。

memcmp は構造を比較せず、 memcmp はバイナリを比較し、構造体には常にゴミがあるため、比較では常にFalseになります。

要素ごとにその安全性を比較し、失敗しません。

構造体にプリミティブのみが含まれている場合、または厳密な等価性に興味がある場合は、次のようなことができます。

int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs)
{
    return memcmp(lhs, rsh, sizeof(struct my_struct));
}

ただし、構造体に他の構造体または共用体へのポインタが含まれている場合は、プリミティブを適切に比較する関数を作成し、必要に応じて他の構造体に対して比較呼び出しを行う必要があります。

ただし、ADT の初期化の一環として、 memset(&a, sizeof(struct my_struct), 1) を使用して構造体のメモリ範囲をゼロにする必要があることに注意してください。

2つの構造体変数がcallocで初期化されているか、memsetによって0に設定されているため、2つの構造体をmemcmpと比較でき、構造体のゴミの心配がなく、時間を稼ぐことができます

この準拠例では、Microsoft Visual Studioの#pragma packコンパイラー拡張機能を使用して、構造体のメンバーができるだけ密にパックされるようにします。

#include <string.h>

#pragma pack(push, 1)
struct s {
  char c;
  int i;
  char buffer[13];
};
#pragma pack(pop)

void compare(const struct s *left, const struct s *right) { 
  if (0 == memcmp(left, right, sizeof(struct s))) {
    /* ... */
  }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top