Come si confrontano due istanze di strutture per l'uguaglianza nella norma C?
Come si confrontano due istanze di strutture per l'uguaglianza nella norma C?
Risposte:
C non offre strutture linguistiche per farlo - devi farlo tu stesso e confrontare ogni membro della struttura per membro.
0.0, -0.0 NaN
è un problema memcmp()
. I puntatori che differiscono nella rappresentazione binaria possono puntare alla stessa posizione (es. DOS: seg: offset) e quindi sono uguali. Alcuni sistemi hanno più puntatori null che si confrontano equamente. Lo stesso per oscuri int
con -0 e tipi in virgola mobile con codifiche ridondanti. (Intel long double, decimal64, ecc.) Questi problemi non fanno differenza calloc()
o vengono utilizzati o riempiti.
==
non funziona con le strutture (come me), si prega di consultare stackoverflow.com/questions/46995631/...
Potresti essere tentato di usarlo memcmp(&a, &b, sizeof(struct foo))
, ma potrebbe non funzionare in tutte le situazioni. Il compilatore può aggiungere spazio buffer di allineamento a una struttura e i valori trovati in posizioni di memoria che si trovano nello spazio buffer non sono garantiti come alcun 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 puntatori, corrisponderà solo se l'indirizzo a cui puntano i puntatori è lo stesso).
memcmp
purché la memoria sia stata prima cancellata. Che è vicino al lavoro ma non corretto. Inoltre, la domanda non definisce "uguaglianza", quindi se la prendi nel significato di "uguaglianza byte-byte della rappresentazione dell'oggetto", lo memcmp
fa esattamente (se la memoria viene cancellata o meno).
Se lo fai molto suggerirei di scrivere una funzione che confronta le due strutture. In questo modo, se dovessi mai cambiare la struttura, dovrai solo cambiare il confronto in un unico posto.
Per quanto riguarda come farlo .... Devi confrontare ogni elemento singolarmente
Non è possibile utilizzare memcmp per confrontare le strutture per l'uguaglianza a causa di potenziali caratteri di riempimento casuale tra il campo 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 tra i membri per essere sicuro.
@Greg ha ragione nel dire che è necessario scrivere funzioni di confronto esplicite nel caso generale.
È possibile utilizzare memcmp
se:
NaN
.-Wpadded
con clang per verificare ciò) OPPURE le strutture sono inizializzate esplicitamente con l' memset
inizializzazione.BOOL
) che hanno valori distinti ma equivalenti.A meno che tu non stia programmando per sistemi embedded (o scrivendo una libreria che potrebbe essere usata 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 conosco ha più NULL
puntatori.
Un'altra opzione è di generare automaticamente le funzioni di uguaglianza. Se disponi le definizioni di struct in modo semplice, è possibile utilizzare una semplice elaborazione di testo per gestire definizioni di struct semplici. Puoi usare libclang per il caso generale, poiché usa lo stesso frontend di Clang, gestisce correttamente tutti i casi angolari (escludendo i bug).
Non ho visto una tale libreria di generazione di codice. Tuttavia, sembra relativamente semplice.
Tuttavia, è anche vero che tali funzioni di uguaglianza generate spesso farebbero la cosa sbagliata a livello di applicazione. Ad esempio, due UNICODE_STRING
strutture in Windows devono essere confrontate in modo superficiale o profondo?
memset
, ecc non garantisce il valore dei bit di riempimento dopo ulteriori operazioni di scrittura ad un elemento struct, vedi: stackoverflow.com/q/52684192/689161
Nota che puoi usare memcmp () su strutture non statiche senza preoccuparti dell'imbottitura, purché non inizializzi tutti i membri (contemporaneamente). Questo è definito da C90:
{0, }
azzererà anche i byte di riempimento?
Dipende se la domanda che stai ponendo è:
Per scoprire se sono lo stesso oggetto, confronta i puntatori con le 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, è possibile 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 cosa significa 'uguale a' per ogni membro - è ovvio per gli inte ma più sottile quando si tratta di valori in virgola mobile o tipi definiti dall'utente.
memcmp
non confronta la struttura, memcmp
confronta il binario, e c'è sempre spazzatura nella struttura, quindi viene sempre fuori Falso in confronto.
Confronta elemento per elemento è sicuro e non fallisce.
Se le strutture contengono solo primitive o se sei interessato a una rigorosa 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 effettuare chiamate di confronto con le altre strutture come appropriato.
Tieni presente, tuttavia, che avresti dovuto utilizzare memset (& a, sizeof (struct my_struct), 1) per azzerare l'intervallo di memoria delle strutture come parte dell'inizializzazione di ADT.
Questo esempio conforme utilizza l'estensione del compilatore #pragma pack di Microsoft Visual Studio per garantire che i membri della struttura siano impacchettati il più strettamente possibile:
#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))) {
/* ... */
}
}