Come confronti le strutture per l’uguaglianza in C?

Come confronti due istanze di strutture per l’uguaglianza nello standard C?

C non fornisce servizi linguistici per farlo: devi farlo tu stesso e confrontare ogni membro della struttura per membro.

Potresti essere tentato di usare memcmp(&a, &b, sizeof(struct foo)) , ma potrebbe non funzionare in tutte le situazioni. Il compilatore può aggiungere spazio di buffer di allineamento a una struttura e non si garantisce che i valori trovati nelle posizioni di memoria che si trovano nello spazio del buffer siano un valore particolare.

Ma, se usi calloc o memset l’intera dimensione delle strutture prima di usarle, puoi fare un confronto superficiale con memcmp (se la tua struttura contiene dei puntatori, corrisponderà solo se l’indirizzo a cui puntano i puntatori sono gli stessi).

Se lo fai molto ti suggerirei di scrivere una funzione che paragona le due strutture. In questo modo, se cambi la struttura, devi solo modificare il confronto in un unico punto.

Per quanto riguarda come farlo …. È necessario confrontare ogni elemento singolarmente

Non è ansible utilizzare memcmp per confrontare le strutture per l’uguaglianza a causa di potenziali caratteri di riempimento casuale tra i campi nelle strutture.

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

Quanto sopra fallirebbe per una struttura come questa:

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

Devi usare il confronto membro-saggio per essere sicuro.

Nota puoi usare memcmp () su strutture non statiche senza preoccuparti del padding, purché non inizializzi tutti i membri (in una volta). Questo è definito da C90:

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

@Greg è corretto che si debbano scrivere funzioni di confronto esplicite nel caso generale.

È ansible utilizzare memcmp se:

  • le strutture non contengono campi a virgola mobile che sono probabilmente NaN .
  • le struct non contengono padding (usa -Wpadded with clang per verificarlo) OPPURE le structs sono inizializzate esplicitamente con memset all’inizializzazione.
  • non ci sono tipi di membri (come Windows BOOL ) che hanno valori distinti ma equivalenti.

A meno che non si stia programmando per sistemi embedded (o scrivendo una libreria che potrebbe essere utilizzata su di essi), non mi preoccuperei di alcuni casi angolari nello standard C. La distinzione tra puntatore vicino e lontano non esiste su nessun dispositivo a 32 o 64 bit. Nessun sistema non incorporato che io conosca ha più puntatori NULL .

Un’altra opzione è quella di generare automaticamente le funzioni di uguaglianza. Se si definiscono le definizioni della struct in modo semplice, è ansible utilizzare una semplice elaborazione del testo per gestire semplici definizioni di struct. Puoi usare libclang per il caso generale – dal momento che usa lo stesso frontend di Clang, gestisce correttamente tutti i casi d’angolo (salvo errori).

Non ho visto una tale libreria di generazione del codice. Tuttavia, sembra relativamente semplice.

Tuttavia, è anche il caso che tali funzioni di uguaglianza generate spesso fanno la cosa sbagliata a livello di applicazione. Ad esempio, due strutture UNICODE_STRING in Windows possono essere confrontate superficialmente o profondamente?

memcmp non confronta la struttura, memcmp confronta il binario, e c’è sempre garbage nella struct, quindi esce sempre False in confronto.

Confronta elemento per elemento è sicuro e non fallisce.

Se le strutture contengono solo primitive o se sei interessato alla stretta uguaglianza, puoi fare qualcosa del genere:

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

Tuttavia, se le tue strutture contengono puntatori ad altre strutture o unioni, dovrai scrivere una funzione che confronta correttamente le primitive ed effettua le chiamate di confronto con le altre strutture come appropriato.

Si noti, tuttavia, che si dovrebbe aver utilizzato memset (& a, sizeof (struct my_struct), 1) per azzerare l’intervallo di memoria delle strutture come parte dell’inizializzazione ADT.

Dipende se la domanda che stai ponendo è:

  1. Queste due strutture sono lo stesso object?
  2. Hanno lo stesso valore?

Per scoprire se sono lo stesso object, confronta i puntatori alle due strutture per l’uguaglianza. Se vuoi scoprire in generale se hanno lo stesso valore devi fare un confronto profondo. Ciò comporta il confronto di tutti i membri. Se i membri sono puntatori ad altre strutture, è necessario ricorrere anche a quelle strutture.

Nel caso speciale in cui le strutture non contengono puntatori, è ansible eseguire un memcmp per eseguire un confronto bit a bit dei dati contenuti in ciascuno senza dover sapere cosa significano i dati.

Assicurati di sapere che cosa significa “uguale” per ogni membro: è ovvio per gli inte ma più sottile quando si tratta di valori in virgola mobile o tipi definiti dall’utente.

se la variabile 2 strutture è inizializzata con calloc o sono impostate con 0 da memset in modo da poter confrontare le tue 2 strutture con memcmp e non ci sono preoccupazioni per la struttura spazzatura e questo ti permetterà di guadagnare tempo

Questo esempio di conformità utilizza l’estensione del compilatore #pragma pack di Microsoft Visual Studio per garantire che i membri della struttura siano impacchettati il ​​più strettamente ansible:

 #include  #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))) { /* ... */ } }