Question

Comment comparez-vous deux instances de structures pour l’égalité en C standard?

Était-ce utile?

La solution

C ne fournit aucune installation linguistique pour cela. Vous devez le faire vous-même et comparer chaque membre de structure par membre.

Autres conseils

Vous pourriez être tenté d'utiliser memcmp (& a, & amp, 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 une superficielle 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. De cette façon, si vous changez la structure, il vous suffit de changer la comparaison à un endroit.

En ce qui concerne la procédure à suivre .... 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.

Notez que vous pouvez utiliser memcmp () sur des structures non statiques sans se soucier du rembourrage, 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 structures ne contiennent aucun champ à virgule flottante pouvant être NaN .
  • les structures ne contiennent pas de remplissage (utilisez -Wpadded avec clang pour vérifier cela) OU les structures sont explicitement initialisées avec memset à l'initialisation.
  • aucun type de membre (tel que Windows BOOL ) ne possède 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. Je ne connais aucun système non intégré qui possède plusieurs 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 & # 8211; comme il utilise la même interface que Clang, il gère correctement tous les virages (à l’exception des 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?

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’il s’agit du même objet, comparez les pointeurs sur les deux structures pour obtenir l’égalité. Si vous voulez savoir en général si elles ont la même valeur, vous devez faire 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 à nouveau.

Dans le cas particulier où les structures ne contiennent pas de pointeurs, vous pouvez faire un memcmp pour effectuer une comparaison au niveau du bit des données contenues dans chacune sans avoir à savoir ce que cela signifie.

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.

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.

Compare élément par élément son coffre-fort et n’échoue pas.

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)
{
    return memcmp(lhs, rsh, sizeof(struct my_struct));
}

Toutefois, 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 toutefois que vous devez avoir utilisé memset (& amp; a, sizeof (struct my_struct), 1) pour mettre à zéro la plage de mémoire des structures dans le cadre de votre initialisation ADT.

si les variables de 2 structures sont initialisées avec calloc ou si elles sont définies avec 0 par memset afin que vous puissiez comparer vos 2 structures avec memcmp.

Cet exemple conforme utilise l'extension de compilateur #pragma pack de Microsoft Visual Studio pour garantir que les membres de la structure sont compressés le plus étroitement 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))) {
    /* ... */
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top