Hvordan sammenligner du structs for likestilling i C?

stemmer
177

Hvordan kan du sammenligne to tilfeller av structs for likestilling i standard C?

Publisert på 26/09/2008 klokken 20:21
kilden bruker
På andre språk...                            


11 svar

stemmer
165

C gir ingen språktjenester å gjøre dette - du må gjøre det selv, og sammenligne hver struktur medlem av medlem.

Svarte 26/09/2008 kl. 20:22
kilden bruker

stemmer
95

Du kan bli fristet til å bruke memcmp(&a, &b, sizeof(struct foo)), men det kan ikke fungere i alle situasjoner. Kompilatoren kan legge innretting buffer plass til en struktur, og de verdier som er funnet på hukommelsessteder som ligger i bufferområder som ikke er garantert å være en hvilken som helst spesiell verdi.

Men, hvis du bruker calloceller memsetfull størrelse av strukturene før du bruker dem, du kan gjøre en grunne sammenligning med memcmp(hvis strukturen inneholder pekere, vil det matche bare hvis adressen pekere peker til er det samme).

Svarte 26/09/2008 kl. 20:32
kilden bruker

stemmer
19

Hvis du gjør det mye jeg ville foreslå å skrive en funksjon som sammenligner de to strukturene. På den måten, hvis du noen gang endre strukturen du trenger bare å endre sammenligne på ett sted.

Som for hvordan du gjør det .... Du må sammenligne hvert element individuelt

Svarte 26/09/2008 kl. 20:24
kilden bruker

stemmer
17

Du kan ikke bruke memcmp å sammenligne structs for likestilling på grunn av potensielle tilfeldig padding tegn mellom felt i structs.

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

Ovennevnte ville mislykkes for en struct som dette:

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

Du må bruke medlem messig sammenligning for å være trygg.

Svarte 26/09/2008 kl. 20:34
kilden bruker

stemmer
5

@Greg er riktig at man må skrive eksplisitte sammenligning funksjoner i det generelle tilfellet.

Det er mulig å bruke memcmpdersom:

  • de structs inneholder ingen flytende komma felt som er mulig NaN.
  • de structs inneholder ingen padding (bruk -Wpaddedmed klang å sjekke dette) eller structs er eksplisitt initialisert med memsetpå initialisering.
  • det er ingen medlemstyper (for eksempel Windows BOOL) som har forskjellige, men likeverdige verdier.

Med mindre du programmerer for embedded systemer (eller skrive et bibliotek som kan brukes på dem), ville jeg ikke bekymre deg om noen av hjørne tilfeller i C-standarden. Den nesten vs. langt peker forskjell eksisterer ikke på noen 32- eller 64- bits-anordning. Ingen ikke-integrert system som jeg kjenner har av flere NULLpekere.

Et annet alternativ er å automatisk generere likestilling funksjoner. Hvis du legger dine struct definisjoner på en enkel måte, er det mulig å bruke enkel tekstbehandling til å håndtere enkle struct definisjoner. Du kan bruke libclang for det generelle tilfellet - siden den bruker samme frontend som klang, den håndterer alle hjørne tilfeller riktig (sperring bugs).

Jeg har ikke sett en slik kode generasjon bibliotek. Det synes imidlertid relativt enkel.

Men det er også slik at slike generert likestillings funksjoner vil ofte gjøre gale ting på applikasjonsnivå. For eksempel bør to UNICODE_STRINGstructs i Windows sammenlignes grunt eller dypt?

Svarte 19/08/2015 kl. 05:39
kilden bruker

stemmer
5

Merk at du kan bruke memcmp () på ikke statiske konstruksjoner uten å bekymre padding, så lenge du ikke initialisere alle medlemmer (samtidig). Dette er definert av C90:

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

Svarte 26/09/2008 kl. 20:52
kilden bruker

stemmer
2

memcmpikke sammenligne struktur, memcmpsammenligner det binære, og det er alltid søppel i struct, derfor er det alltid kommer ut False i sammenligning.

Sammenligne element for element sin trygge og svikter ikke.

Svarte 07/08/2012 kl. 19:15
kilden bruker

stemmer
1

Det avhenger av om spørsmålet du stiller er:

  1. Er disse to structs det samme objektet?
  2. Har de samme verdi?

For å finne ut om de er det samme objektet, sammenligne pekere til de to structs for likestilling. Hvis du ønsker å finne ut generelt om de har den samme verdien du trenger å gjøre en dyp sammenligning. Dette innebærer å sammenligne alle medlemmene. Dersom medlemmene er pekere til andre structs du trenger å recurse inn i disse structs også.

I det spesielle tilfellet hvor structs ikke inneholder tips du kan gjøre for en memcmp å utføre en bitvis sammenligning av de data som finnes i hver uten å vite hva dataene betyr.

Sørg for at du vet hva som er lik "betyr for hvert medlem - det er åpenbart for ints men mer subtil når det gjelder flyttallsverdier eller brukerdefinerte typer.

Svarte 27/09/2008 kl. 14:41
kilden bruker

stemmer
1

Hvis structs bare inneholde primitiver eller hvis du er interessert i streng likestilling så kan du gjøre noe som dette:

int my_struct_cmp (konst struct my_struct * lhs, const struct my_struct * RHS)
{
    returnere memcmp (LHS, rsh, sizeof (struct my_struct));
}

Men hvis structs inneholde pekere til andre structs eller fagforeninger da må du skrive en funksjon som sammenligner primitive riktig måte og gjøre sammenligning anrop mot de andre strukturene som passer.

Vær imidlertid oppmerksom på at du bør ha brukt memset (og en, sizeof (struct my_struct), 1) for å nullstille minnet spekter av strukturene som en del av ADT initialisering.

Svarte 26/09/2008 kl. 20:34
kilden bruker

stemmer
-1

hvis de 2 strukturer variable er initialied med calloc eller de er satt med 0 etter memset slik at du kan sammenligne dine 2 strukturer med memcmp og det er ingen grunn til bekymring om struktur søppel og dette vil tillate deg å tjene tid

Svarte 03/10/2012 kl. 09:11
kilden bruker

stemmer
-2

Dette kompatibel eksemplet bruker #pragma pakke kompilatoren forlengelse fra Microsoft Visual Studio for å sikre strukturen medlemmer er pakket så tett som mulig:

#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))) {
    /* ... */
  }
}
Svarte 30/09/2014 kl. 17:06
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more