Est-ce que la méthode defacto pour comparer des tableaux (en C) utilise memcmp
partir de ssortingng.h
?
Je veux comparer des tableaux d’ints et de doubles dans mes tests unitaires
Je ne suis pas sûr d’utiliser quelque chose comme:
double a[] = {1.0, 2.0, 3.0}; double b[] = {1.0, 2.0, 3.0}; size_t n = 3; if (! memcmp(a, b, n * sizeof(double))) /* arrays equal */
ou pour écrire une fonction de type is_array_equal(a, b, n)
mesure?
memcmp
ferait une comparaison exacte , ce qui est rarement une bonne idée pour les flotteurs et ne suivrait pas la règle NaN! = NaN. Pour le sorting, c’est bien, mais à d’autres fins, vous pouvez effectuer une comparaison approximative telle que:
bool dbl_array_eq(double const *x, double const *y, size_t n, double eps) { for (size_t i=0; i eps) return false; return true; }
Remplacez memset
par memcmp
dans votre code, et cela fonctionne.
Dans votre cas (comme la taille des tableaux de tableaux sont identiques et connus lors de la compilation), vous pouvez même faire:
memcmp(a, b, sizeof(a));
L’utilisation de memcmp
n’est généralement pas une bonne idée. Commençons par les plus complexes et travaillons à partir de là.
Bien que vous ayez mentionné int
et double
, je voudrais d’abord me concentrer sur memcmp
tant que solution générale, telle que la comparaison de tableaux de types:
struct { char c; // 1 int i; // 2 }
Le principal problème réside dans le fait que les implémentations sont libres d’append du rembourrage aux structures des emplacements 1 et 2, ce qui rend potentiellement fausse une comparaison octet par octet, même si les bits importants correspondent parfaitement.
Maintenant en double. Vous pourriez penser que c’était mieux car il n’y a pas de rembourrage ici. Cependant, il y a d’autres problèmes.
Le premier est le traitement des valeurs de NaN
. IEEE754 fait tout son possible pour s’assurer que NaN
n’est égal à aucune autre valeur, y compris elle-même. Par exemple, le code:
#include #include int main (void) { double d1 = 0.0 / 0.0, d2 = d1; if (d1 == d2) puts ("Okay"); else puts ("Bad"); if (memcmp (&d1, &d2, sizeof(double)) == 0) puts ("Okay"); else puts ("Bad"); return 0; }
va sortir
Bad Okay
illustrant la différence.
La seconde est le traitement du plus et du moins zéro. Ceux-ci doivent être considérés comme égaux aux fins de la comparaison, mais, comme les modèles de bits sont différents, memcmp
dira qu’ils sont différents.
Changer la déclaration / initialisation de d1
et d2
dans le code ci-dessus en:
double d1 = 0.0, d2 = -d1;
rendra cela clair.
Donc, si les structures et les doubles sont problématiques, il est certain que les entiers vont bien. Après tout, ils sont toujours deux compléments, non?
Non, en fait ils ne sont pas. L’ISO impose l’un des trois schémas de codage pour les entiers signés et les deux autres (les compléments et le signe / magnitude) souffrent d’un problème similaire à celui des doublons, à savoir qu’il existe à la fois zéro et plus.
Ainsi, bien qu’ils puissent éventuellement être considérés comme égaux, les modèles de bits sont à nouveau différents.
Même pour les entiers non signés , vous avez un problème (c’est également un problème pour les valeurs signées). ISO indique que ces représentations peuvent avoir des bits de valeur et des bits de remplissage, et que les valeurs des bits de remplissage ne sont pas spécifiées.
Ainsi, même pour ce qui peut sembler le cas le plus simple, memcmp
peut être une mauvaise idée.
La fonction que vous recherchez est memcmp
, pas memset
. Voir les réponses à cette question pour savoir pourquoi ce ne serait peut-être pas une bonne idée de memcmp
un tableau de doublons.
memcmp compare deux blocs de mémoire pour le nombre de taille donné
memset est utilisé pour initialiser le tampon avec une valeur de taille donnée
Les tampons peuvent être comparés sans utiliser memcmp de la manière suivante. même peut être changé pour différents types de données.
int8_t array_1[] = { 1, 2, 3, 4 } int8_t array_2[] = { 1, 2, 3, 4 } uint8_t i; uint8_t compare_result = 1; for (i = 0; i < (sizeof(array_1)/sizeof(int8_t); i++) { if (array_1[i] != array_2[i]) { compare_result = 0; break; } }