memcmp vs strcmp en C : octets, chaînes et longueurs
memcmp compare n octets, strcmp s'arrête au nul. Observe leurs résultats, distingue préfixe et buffer complet, puis pratique les comparaisons en C.
Deux tableaux contiennent le même texte, mais leur comparaison mémoire annonce une différence. Avant de changer la condition, regarde ce que tu veux comparer : la chaîne terminée par un nul, un préfixe ou le buffer entier.
En bref
strcmp(3) compare deux chaînes jusqu'à leur terminateur nul ; memcmp(3) compare les n premiers octets des deux zones, y compris les octets nuls. Les deux interprètent les octets comme des unsigned char et renvoient un entier négatif, nul ou positif. Pour tester l'égalité de deux buffers complets, vérifie aussi leurs longueurs : un préfixe égal ne suffit pas.
Pourquoi le même texte donne-t-il deux résultats ?
Le texte s'arrête au premier '\0'. Les octets qui suivent appartiennent encore au tableau, mais plus à cette chaîne. Ce programme initialise chaque case : aucune valeur indéterminée n'intervient dans le résultat.
#include <stdio.h>#include <string.h>
int main(void){ const char a[] = {'A', '\0', 'X'}; const char b[] = {'A', '\0', 'Y'}; const unsigned char high[] = {0xff}; const unsigned char low[] = {0x01};
printf("strcmp(a, b) == 0: %d\n", strcmp(a, b) == 0); printf("memcmp(a, b, 2) == 0: %d\n", memcmp(a, b, 2) == 0); printf("memcmp(a, b, 3) < 0: %d\n", memcmp(a, b, 3) < 0); printf("memcmp(high, low, 1) > 0: %d\n", memcmp(high, low, 1) > 0); printf("memcmp(a, b, 0) == 0: %d\n", memcmp(a, b, 0) == 0); return 0;}$ gcc -std=c17 -Wall -Wextra -Werror compare.c -o compare$ ./comparestrcmp(a, b) == 0: 1memcmp(a, b, 2) == 0: 1memcmp(a, b, 3) < 0: 1memcmp(high, low, 1) > 0: 1memcmp(a, b, 0) == 0: 1La première ligne vaut 1 car les deux chaînes sont "A". Sur deux octets, les zones mémoire sont aussi identiques : 'A' puis '\0'. Sur trois, la comparaison atteint 'X' et 'Y'. Ici, leur ordre donne un résultat négatif.
- a[0]'A'
- a[1]'\0'fin de la chaîne
- a[2]'X'encore dans le buffer
Dans b, seule la dernière case contient 'Y'. Le terminateur est un octet de valeur zéro, pas le caractère '0'. Une chaîne vide commence directement par ce terminateur. Pour reprendre les bases du stockage, consulte le guide des chaînes en C.
Quelle taille donner pour comparer deux buffers complets ?
Les longueurs doivent être égales avant de comparer leur contenu. Sinon, lire seulement la longueur du plus court établit l'égalité d'un préfixe, pas celle des buffers.
#include <stddef.h>#include <stdio.h>#include <string.h>
int same_bytes(const void *a, size_t na, const void *b, size_t nb){ if (na != nb) return 0; if (na == 0) return 1; return memcmp(a, b, na) == 0;}
int main(void){ const unsigned char a[] = {'A'}; const unsigned char b[] = {'A', 'B'}; printf("prefix: %d\n", memcmp(a, b, sizeof a) == 0); printf("whole: %d\n", same_bytes(a, sizeof a, b, sizeof b)); printf("equal: %d\n", same_bytes(b, sizeof b, b, sizeof b)); printf("empty: %d\n", same_bytes(NULL, 0, NULL, 0)); return 0;}$ gcc -std=c17 -Wall -Wextra -Werror buffers.c -o buffers$ ./buffersprefix: 1whole: 0equal: 1empty: 1La première comparaison lit un seul octet : 'A'. Elle ne dit rien du 'B' supplémentaire. same_bytes refuse d'abord les longueurs différentes, puis compare tous les octets lorsque les longueurs coïncident.
Ce helper a un contrat précis : pour une longueur non nulle, chaque pointeur désigne au moins autant d'octets lisibles. Pour deux longueurs nulles, il renvoie avant tout appel à la bibliothèque ; il accepte donc ici deux pointeurs NULL. N'en déduis pas que tu peux passer NULL à memcmp(3), même avec une taille nulle.
sizeof a mesure le tableau local de cet exemple. Dans une fonction qui reçoit un pointeur, sizeof mesure le pointeur, pas la taille de la zone pointée. Passe la longueur séparément, comme ici. Le tableau et le pointeur n'ont pas le même type.
Pourquoi tester le signe plutôt que -1 ou 1 ?
Le contrat garantit le signe du résultat, pas sa valeur exacte. Écris < 0, == 0 ou > 0. La troisième ligne de compare.c transforme volontairement le résultat en une condition : le 1 affiché signifie « vrai », pas « la bibliothèque a renvoyé 1 ».
La comparaison lit les octets comme des unsigned char. La ligne avec 0xff et 0x01 vérifie que 255 vient après 1, même sur une machine où un char ordinaire peut être signé. Une réécriture qui soustrait directement deux char peut donc inverser l'ordre pour les octets élevés.
Pour l'égalité, if (memcmp(a, b, n)) entre dans la branche quand les zones diffèrent. Le test explicite == 0 évite de confondre égalité et vérité.
memcmp
Implémente la comparaison octet par octet. Les cas évalués traversent un nul interne, s'arrêtent à la borne demandée et comparent aussi des octets supérieurs à 127.
Quelle fonction choisir selon les données ?
Choisis selon le contrat de tes données, avant de choisir une fonction.
Que représentent les données ?
Deux chaînes terminées
strcmp
Le nul marque la fin du texte ; les octets suivants ne font pas partie de la chaîne.
Deux buffers binaires
Longueurs puis memcmp
Les nuls sont des données ; pour une égalité complète les tailles doivent coïncider.
Deux structures C
Comparer les champs utiles
Les octets de bourrage et les représentations mémoire ne définissent pas une égalité métier.
Une structure peut contenir du bourrage entre ses champs. Deux valeurs égales champ par champ ne sont donc pas nécessairement identiques octet par octet. Pour des tableaux d'entiers, une comparaison mémoire n'est pas non plus un tri numérique : l'ordre des octets dépend de leur représentation.
Comparer ne copie rien. Si ton problème est de déplacer des octets vers une autre zone, lis plutôt la différence entre memcpy et memmove.
strcmp
Reprends ensuite le cas des chaînes : le parcours doit s'arrêter au terminateur commun, tout en détectant une chaîne qui prolonge l'autre.
Questions fréquentes
memcmp s'arrête-t-il au premier octet nul ?
Non. Un nul compte comme n'importe quel octet dans la zone demandée. Une différence située après lui peut déterminer le résultat.
Comparer le minimum des longueurs suffit-il ?
Pour tester un préfixe commun, oui, à condition que les zones soient lisibles. Pour tester l'égalité complète, non : il faut aussi vérifier l'égalité des longueurs.
strcmp trie-t-il les mots dans l'ordre d'une langue ?
Non. Il compare les codes des octets ; ce n'est pas une collation linguistique. Un texte UTF-8 reste une suite d'octets pour cette fonction.
Puis-je comparer un secret avec memcmp ?
Cette fonction ne garantit pas un temps indépendant du contenu. Pour des secrets cryptographiques, utilise la primitive de comparaison prévue par ta bibliothèque de cryptographie.
Sources
