Comment comparez-vous les structures pour l’égalité dans C?

Comment comparez-vous deux instances de struct pour l’égalité dans la norme C?

C ne fournit aucune possibilité de faire cela: vous devez le faire vous-même et comparer chaque membre de la structure par membre.

Vous pourriez être tenté d’utiliser memcmp(&a, &b, sizeof(struct foo)) , mais cela peut ne pas fonctionner dans toutes les situations. Le compilateur peut append un espace tampon d’alignement à une structure et les valeurs trouvées dans les emplacements de mémoire situés dans l’espace tampon ne sont pas garanties.

Mais, si vous utilisez calloc ou memset la taille complète des structures avant de les utiliser, vous pouvez effectuer une comparaison superficielle avec memcmp (si votre structure contient des pointeurs, elle ne correspondra que si l’adresse indiquée par les pointeurs est la même).

Si vous le faites beaucoup, je vous suggère d’écrire une fonction qui compare les deux structures. De cette façon, si vous changez la structure, il vous suffit de modifier la comparaison au même endroit.

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

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

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

Ce qui précède échouerait pour une structure comme celle-ci:

 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.

Notez que vous pouvez utiliser memcmp () sur des structures non statiques sans vous soucier du remplissage, tant que vous n’initialisez pas tous les membres (à la fois). Ceci est défini par C90:

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

@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 structs ne contiennent pas de champs à virgule flottante pouvant être NaN .
  • les structures ne contiennent aucun remplissage (utilisez -Wpadded avec clang pour vérifier cela) OU les structures sont explicitement initialisées avec memset lors de l’initialisation.
  • aucun type de membre (tel que Windows BOOL ) ne possède des valeurs distinctes mais équivalentes.

Sauf si vous programmez des systèmes embarqués (ou écrivez une bibliothèque qui pourrait être utilisée sur ces systèmes), je ne m’inquiéterais pas de certains cas particuliers dans le standard C. La distinction entre le pointeur proche et le pointeur distant n’existe sur aucun périphérique 32 ou 64 bits. Aucun système non intégré que je connais ne possède plusieurs pointeurs NULL .

Une autre option consiste à générer automatiquement les fonctions d’égalité. Si vous déposez vos définitions de structure de manière simple, il est possible d’utiliser un traitement de texte simple pour gérer des définitions de structure simples. Vous pouvez utiliser libclang pour le cas général: comme il utilise le même frontal que Clang, il gère tous les casiers d’angle (sauf les bogues).

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

Cependant, il est également vrai que de telles fonctions d’égalité générées feraient souvent une erreur au niveau de l’application. Par exemple, deux structures UNICODE_STRING de Windows doivent-elles être comparées superficiellement ou profondément?

memcmp ne compare pas la structure, memcmp compare le binary, et il y a toujours des erreurs dans la structure, donc ça sort toujours en comparaison.

Comparer élément par élément son sans danger et ne pas échouer.

Si les structures ne contiennent que des primitives ou si vous êtes intéressé par une égalité ssortingcte, vous pouvez faire quelque chose comme ceci:

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

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

Sachez cependant que vous devriez avoir utilisé 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.

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

  1. Ces deux structures sont-elles le même object?
  2. Ont-ils la même valeur?

Pour savoir s’ils sont le même object, comparez les pointeurs aux deux structures pour l’égalité. Si vous voulez savoir en général s’ils ont la même valeur, vous devez effectuer une comparaison approfondie. Cela implique de comparer tous les membres. Si les membres sont des pointeurs vers d’autres structures, vous devez également les intégrer à ces structures.

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

Assurez-vous de savoir ce que signifie «égal» pour chaque membre – il est évident pour ints mais plus subtile lorsqu’il s’agit de valeurs à virgule flottante ou de types définis par l’utilisateur.

Si la variable 2 structures est initialisée avec calloc ou si elle est définie par 0 par memset, vous pouvez comparer vos 2 structures avec memcmp et vous ne vous souciez pas de la structure de la mémoire et cela vous permettra de gagner du temps

Cet exemple conforme utilise l’extension #pragma pack comstackr de Microsoft Visual Studio pour garantir que les membres de la structure sont compressés aussi étroitement que possible:

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