Comment comparez-vous les structures pour l'égalité en C?

Comment voulez-vous comparer les deux instances de structures pour l'égalité dans la norme C?

178
demandé sur Hans Sjunnesson 2008-09-27 00:21:23

11 réponses

c n'offre pas de facilités linguistiques pour faire cela - vous devez le faire vous-même et comparer chaque membre de la structure.

165
répondu Greg Hewgill 2008-09-26 20:22:14

Vous pouvez être tenté d'utiliser memcmp(&a, &b, sizeof(struct foo)) , mais il peut ne pas fonctionner dans toutes les situations. Le compilateur peut ajouter de l'espace tampon d'alignement à une structure, et les valeurs trouvées aux emplacements de mémoire situés dans l'espace tampon ne sont pas garanties d'être une valeur particulière.

mais, si vous utilisez calloc ou memset la taille complète des structures avant de les utiliser, vous can faire un peu profond comparaison avec memcmp (si votre structure contient des pointeurs, elle ne correspondra que si l'adresse pointée par les pointeurs est la même).

95
répondu Sufian 2016-03-22 06:51:25

Si vous faites beaucoup je suggère d'écrire une fonction qui compare les deux structures. De cette façon, si jamais vous changez la structure, vous devez seulement changer les comparer en un seul endroit.

quant à la façon de le faire.... Vous devez comparer chaque élément individuellement

19
répondu Ben 2008-09-26 20:24:32

vous ne pouvez pas utiliser memcmp pour comparer des structures pour l'égalité en raison de caractères de remplissage aléatoires potentiels entre les zones dans les structures.

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

ci-dessus serait un échec pour une structure comme ceci:

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

vous devez utiliser la comparaison par membre pour être sûr.

17
répondu 2008-09-26 20:34:12

Note Vous pouvez utiliser memcmp() sur des structures non statiques sans s'inquiéter du rembourrage, tant que vous n'initialisez pas tous les membres (à la fois). Elle est définie par C90:

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

5
répondu pixelbeat 2008-09-26 20:52:38

@Greg a raison de dire qu'il faut écrire des fonctions de comparaison explicites dans le cas général.

il est possible d'utiliser memcmp si:

  • les structures ne contiennent pas de champs à virgule flottante qui sont peut-être NaN .
  • les structures ne contiennent pas de rembourrage (utilisez -Wpadded avec clang pour vérifier cela) ou les structures sont explicitement initialisées avec memset à l'initialisation.
  • il n'y a pas de types de membres (tels que Windows BOOL ) qui ont des valeurs distinctes mais équivalentes.

à moins que vous ne programmiez pour des systèmes embarqués (ou écriviez une bibliothèque qui pourrait être utilisée sur eux), je ne me soucierais pas de certains des cas de coin dans le standard C. La distinction entre pointeur proche et pointeur lointain n'existe sur Aucun périphérique de 32 ou 64 bits. Aucun système non intégré que je connaisse n'a plusieurs pointeurs NULL .

une autre option est d'auto-générer les fonctions d'égalité. Si vous disposez vos définitions de struct d'une manière simple, il est possible d'utiliser un traitement de texte simple pour gérer les définitions de struct simples. Vous pouvez utiliser libclang pour le cas général – puisqu'il utilise la même interface que Clang, il gère correctement tous les cas de coin (sauf les bogues).

Je n'ai pas vu une telle bibliothèque de génération de code. Cependant, cela semble relativement simple.

Toutefois, il est également vrai que de telles fonctions d'égalité générées feraient souvent le mauvais choix au niveau de la demande. Par exemple, est-ce que deux structures UNICODE_STRING dans Windows devraient être comparées superficiellement ou profondément?

5
répondu Demi 2017-12-23 19:16:03

memcmp ne compare pas la structure, memcmp compare le binaire, et il y a toujours des déchets dans la structure, donc il sort toujours faux en comparaison.

comparez élément par élément son coffre et ne tombe pas en panne.

2
répondu sergio 2012-10-03 09:03:28

si les structures contiennent seulement des primitives ou si vous êtes intéressé par l'égalité stricte alors vous pouvez faire quelque chose comme ceci:

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

cependant, si vos structures contiennent des pointeurs vers d'autres structures ou unions, alors vous devrez écrire une fonction qui compare correctement les primitives et faire des appels de comparaison avec les autres structures, le cas échéant.

soyez conscient, cependant, que vous auriez dû utiliser memset (&a, sizeof(struct my_struct), 1) pour mettre à zéro la plage de mémoire des structures dans le cadre de votre initialisation ADT.

1
répondu Kevin S. 2008-09-26 20:34:40

cela dépend si la question que vous posez est:

  1. ces deux structures sont-elles le même objet?
  2. ont-ils la même valeur?

pour savoir s'ils sont le même objet, comparez les pointeurs aux deux structures pour l'égalité. Si vous voulez savoir en général si elles ont la même valeur, vous devez faire une comparaison profonde. Il s'agit de comparer tous les membres. Si les membres sont des pointeurs à d'autres structures, vous devez répéter dans ces structures.

dans le cas particulier où les structures ne contiennent pas de pointeurs, vous pouvez faire un memcmp pour effectuer une comparaison en bits des données contenues dans chacune sans avoir à savoir ce que les données signifient.

assurez - vous de savoir ce que "égal" signifie pour chaque membre-c'est évident pour les ints mais plus subtil quand il s'agit de valeurs à virgule flottante ou de types définis par l'utilisateur.

1
répondu domgblackwell 2008-09-27 14:41:58

si la variable 2 structures est initialisée avec calloc ou si elle est définie avec 0 par memset de sorte que vous pouvez comparer vos 2 structures avec memcmp et qu'il n'y a pas de souci à propos des déchets de structure et cela vous permettra de gagner du temps

-1
répondu MOHAMED 2012-10-03 09:11:00

cet exemple conforme utilise l'extension #pragma pack compiler de Microsoft Visual Studio pour s'assurer que les membres de la structure sont emballés aussi étroitement que possible:

#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))) {
    /* ... */
  }
}
-2
répondu Hesham Eraqi 2014-09-30 17:06:41