標準Cで構造体の2つのインスタンスが等しいかどうかをどのように比較しますか?
Cにはこれを行うための言語機能はありません。各自でそれを実行し、メンバーごとに各構造を比較する必要があります。
memcmp(&a, &b, sizeof(struct foo))
を使用したくなるかもしれませんが、すべての状況で機能するとは限りません。コンパイラーは構造体にアライメントバッファースペースを追加する場合があり、バッファースペース内のメモリ位置で見つかった値は特定の値であるとは限りません。
しかし、calloc
またはmemset
を使用する前に構造のフルサイズを使用する場合、can do(shallowmemcmp
との比較(構造体にポインターが含まれる場合、ポインターが指すアドレスが同じ場合にのみ一致します)。
たくさんやるなら、2つの構造を比較する関数を書くことをお勧めします。そうすれば、構造を変更した場合でも、比較を1か所で変更するだけで済みます。
方法については...すべての要素を個別に比較する必要があります
Memcmpを使用して、構造体のフィールド間でランダムなパディング文字が発生する可能性があるため、構造体の等価性を比較することはできません。
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
このような構造体の場合、上記は失敗します。
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
安全のために、メンバーごとの比較を使用する必要があります。
@Gregは、一般的な場合に明示的な比較関数を記述する必要があることは正しいです。
次の場合、memcmp
を使用できます。
NaN
である可能性のある浮動小数点フィールドが含まれていません。-Wpadded
を使用)OR構造体は初期化時にmemset
で明示的に初期化されます。BOOL
など)はありません。組み込みシステム向けのプログラミング(またはそれらで使用される可能性のあるライブラリの作成)をしているのでない限り、C標準の一部のケースについては心配しません。 32ビットまたは64ビットのデバイスには、ニアポインターとファーポインターの区別はありません。私が知っている埋め込みシステムには、複数のNULL
ポインターがありません。
別のオプションは、等式関数を自動生成することです。構造体定義を簡単な方法でレイアウトすると、単純なテキスト処理を使用して単純な構造体定義を処理できます。一般的なケースにはlibclangを使用できます。Clangと同じフロントエンドを使用するため、すべてのコーナーケースを正しく処理します(バグはありません)。
私はそのようなコード生成ライブラリを見たことがありません。ただし、比較的単純に見えます。
ただし、このように生成された等式関数は、アプリケーションレベルで間違った動作をすることがよくあります。たとえば、Windowsの2つのUNICODE_STRING
構造体を浅くまたは深く比較する必要がありますか?
すべてのメンバーを(一度に)初期化しない限り、パディングを気にせずに非静的構造でmemcmp()を使用できることに注意してください。これはC90で定義されています。
memcmp
は構造を比較せず、memcmp
はバイナリを比較し、構造には常にゴミが存在するため、比較では常にFalseになります。
要素ごとに安全を比較し、失敗しません。
それはあなたが尋ねている質問が以下であるかどうかに依存します:
それらが同じオブジェクトであるかどうかを確認するには、2つの構造体へのポインターが等しいかどうかを比較します。それらが同じ値を持っているかどうかを一般的に調べたい場合は、詳細な比較を行う必要があります。これには、すべてのメンバーの比較が含まれます。メンバーが他の構造体へのポインタである場合、それらの構造体にも再帰する必要があります。
構造体にポインターが含まれない特別な場合、memcmpを実行して、データの意味を知らなくても、それぞれに含まれるデータのビットごとの比較を実行できます。
各メンバーの「等しい」の意味を必ず確認してください。intの場合は明らかですが、浮動小数点値またはユーザー定義型の場合はより微妙です。
構造体にプリミティブのみが含まれている場合、または厳密な等価性に関心がある場合は、次のようなことができます。
int my_struct_cmp(const struct my_struct * lhs、const struct my_struct * rhs) { return memcmp(lhs、rsh、sizeof(struct my_struct)); }
ただし、構造体に他の構造体または共用体へのポインターが含まれている場合は、プリミティブを適切に比較し、必要に応じて他の構造体と比較呼び出しを行う関数を作成する必要があります。
ただし、memset(&a、sizeof(struct my_struct)、1)を使用して、ADT初期化の一部として構造体のメモリ範囲をゼロにする必要があることに注意してください。