Comment comparez-vous deux instances de struct pour l'égalité dans C standard?
C ne fournit aucune installation linguistique pour ce faire - vous devez le faire vous-même et comparer chaque structure membre par membre.
Vous pouvez être tenté d'utiliser memcmp(&a, &b, sizeof(struct foo))
, mais cela peut ne pas fonctionner dans toutes les situations. Le compilateur peut ajouter de l’espace tampon d’alignement à une structure et il n’est pas garanti que les valeurs trouvées aux emplacements de mémoire situés dans l’espace tampon soient des valeurs particulières.
Mais si vous utilisez calloc
ou memset
la taille complète des structures avant de les utiliser, vous pouvez faire un peu profonde comparaison avec memcmp
(si votre structure contient des pointeurs, celle-ci ne correspond que si l'adresse indiquée par les pointeurs est identique).
Si vous le faites souvent, je vous suggérerais d’écrire une fonction qui compare les deux structures. Ainsi, si vous modifiez un jour la structure, il vous suffit de modifier la comparaison à un 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 avec une égalité en raison des caractères de remplissage aléatoires potentiels entre les champs de la structure.
// 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 membre par membre pour être sûr.
@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:
NaN
.-Wpadded
avec clang pour vérifier cela) OR les structures sont explicitement initialisées avec memset
à l'initialisation.BOOL
) ayant des valeurs distinctes mais équivalentes.À moins que vous ne programmiez pour des systèmes intégrés (ou que vous n'écriviez pas une bibliothèque qui pourrait être utilisée sur ceux-ci), je ne m'inquiéterais pas de certains cas critiques du standard C. La distinction entre le pointeur proche et lointain n'existe sur aucun périphérique 32 ou 64 bits. À ma connaissance, aucun système non intégré ne comporte de multiples pointeurs NULL
.
Une autre option consiste à générer automatiquement les fonctions d'égalité. Si vous établissez 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 - puisqu'il utilise la même interface que Clang, il gère correctement tous les cas de coin (sauf les bugs).
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 agissent souvent de manière erronée au niveau de l’application. Par exemple, deux structures UNICODE_STRING
dans Windows doivent-elles être comparées superficiellement ou profondément?
Notez que vous pouvez utiliser memcmp () sur des structures non statiques sans vous soucier du remplissage, à condition de ne pas initialiser tous les membres (à la fois). Ceci est défini par C90:
memcmp
ne compare pas la structure, memcmp
compare le binaire, et il y a toujours des ordures dans la structure, elle est donc toujours fausse en comparaison.
Comparez élément par élément et n’échouez pas.
Cela dépend si la question que vous posez est:
Pour savoir s’il s’agit du même objet, 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 insérer dans ces structures.
Dans le cas particulier où les structures ne contiennent pas de pointeurs, vous pouvez créer un memcmp pour effectuer une comparaison au niveau du bit des données contenues dans chacune sans avoir à savoir ce que ces données signifient.
Assurez-vous de savoir ce que signifie "égal" pour chaque membre - cela est évident pour les ints, mais plus subtile lorsqu'il s'agit de valeurs à virgule flottante ou de types définis par l'utilisateur.
Si les structures ne contiennent que des primitives ou si vous êtes intéressé par une égalité stricte, vous pouvez faire quelque chose comme ceci:
int my_struct_cmp (const struct my_struct * lhs, const struct my_struct * rhs) { renvoyer memcmp (lhs, rsh, sizeof (struct my_struct)); }
Cependant, si vos structures contiennent des pointeurs vers d'autres structures ou unions, vous devez écrire une fonction qui compare correctement les primitives et effectuer 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.