Domanda

Come si confrontano due istanze di strutture per l'uguaglianza nella norma C?

È stato utile?

Soluzione

C non offre strutture linguistiche per farlo - devi farlo tu stesso e confrontare ogni membro della struttura per membro.

Altri suggerimenti

Potresti essere tentato di usare memcmp (& amp; a, & amp; 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 a dimensione intera delle strutture prima di usarle, puoi fare un superficiale confronto con memcmp (se la tua struttura contiene puntatori, corrisponderà solo se l'indirizzo a cui puntano i puntatori è lo stesso).

Se lo fai molto suggerirei di scrivere una funzione che paragona 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 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 tra i membri per essere sicuro.

Nota che puoi usare memcmp () su strutture non statiche senza preoccuparsi dell'imbottitura, purché non si inizializzi tutti i membri (contemporaneamente). Questo è definito da C90:

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

@Greg ha ragione nel scrivere in modo esplicito funzioni di confronto nel caso generale.

È possibile utilizzare memcmp se:

  • le strutture non contengono campi in virgola mobile che sono possibilmente NaN .
  • le strutture non contengono alcun riempimento (utilizzare -Wpadded con clang per controllare questo) OPPURE le strutture 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 conosco ha più puntatori NULL .

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 simile 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 strutture UNICODE_STRING in Windows devono essere confrontate in modo superficiale o profondo?

Dipende se la domanda che stai ponendo è:

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

Per scoprire se sono lo stesso oggetto, confrontare 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 risulta sempre False 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 usare memset (& amp; a, sizeof (struct my_struct), 1) per azzerare l'intervallo di memoria delle strutture come parte della tua inizializzazione ADT.

se le variabili delle 2 strutture sono inizializzate con calloc o sono impostate con 0 dal memset in modo da poter confrontare le tue 2 strutture con memcmp e non c'è preoccupazione per la spazzatura delle strutture e questo ti permetterà di guadagnare tempo

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))) {
    /* ... */
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top