Valeur de retour incohérente de strcmp () lors du passage de chaînes sous forme de pointeurs ou de littéraux

Je jouais avec strcmp quand j’ai remarqué ceci, voici le code:

 #include  #include  int main(){ //passing ssortingngs directly printf("%d\n", strcmp("ahmad", "fatema")); //passing ssortingngs as pointers char *a= "ahmad"; char *b= "fatema"; printf("%d\n",strcmp(a,b)); return 0; } 

le résultat est:

 -1 -5 

ne devrait pas fonctionner strcmp même? Pourquoi est-ce que l’on me donne une valeur différente quand je passe des chaînes comme "ahmad" ou comme char* a = "ahmad" . Lorsque vous transmettez des valeurs à une fonction, elles sont allouées dans sa stack, non?

Vous êtes probablement en train de voir le résultat d’une optimisation du compilateur. Si on teste le code en utilisant gcc sur godbolt , avec le niveau d’optimisation -O0 , on peut voir pour le premier cas qu’il n’appelle pas strcmp :

 movl $-1, %esi #, movl $.LC0, %edi #, movl $0, %eax #, call printf # 

Puisque vous utilisez des constantes comme arguments pour strcmp, le compilateur est capable de faire un pliage constant et d’appeler un compilateur insortingnsèque au moment de la compilation et de générer le -1 au lieu d’appeler strcmp à l’exécution implémentée dans la bibliothèque standard. aura une implémentation différente puis un temps de compilation probablement plus simple strcmp .

Dans le second cas, il génère un appel à strcmp :

 call strcmp # movl %eax, %esi # D.2047, movl $.LC0, %edi #, movl $0, %eax #, call printf # 

Ceci est cohérent avec le fait que gcc a une fonction intégrée pour strcmp , ce que gcc utilisera lors du pliage constant.

Si nous testons encore en utilisant le niveau d’optimisation -O1 ou supérieur, gcc est capable de plier les deux cas et le résultat sera -1 pour les deux cas:

 movl $-1, %esi #, movl $.LC0, %edi #, xorl %eax, %eax # call printf # movl $-1, %esi #, movl $.LC0, %edi #, xorl %eax, %eax # call printf # 

Avec un plus grand nombre d’optimisations, l’optimiseur est capable de déterminer que a et b pointent également vers des constantes connues au moment de la compilation et peut également calculer le résultat de strcmp pour ce cas pendant la compilation.

Nous pouvons confirmer que gcc utilise la fonction intégrée en construisant avec l’ indicateur -fno-builtin et en observant qu’un appel à strcmp sera généré pour tous les cas.

clang est légèrement différent en ce sens qu’il ne se plie pas du tout en utilisant -O0 mais se pliera à -O1 et au-dessus pour les deux.

Notez que tout résultat négatif est entièrement conforme, nous pouvons voir en allant dans le brouillon de la norme standard C99 7.21.4.2 la fonction strcmp qui dit

 int strcmp(const char *s1, const char *s2); 

La fonction strcmp renvoie un nombre entier supérieur, égal ou inférieur à zéro , car la chaîne pointée par s1 est supérieure, égale ou inférieure à la chaîne pointée par s2.

technosurus souligne que strcmp est spécifié pour traiter les chaînes comme si elles étaient composées de caractères non signés , ceci est couvert dans C99 sous 7.21.1 qui dit:

Pour toutes les fonctions du présent sous-paragraphe, chaque caractère doit être interprété comme s’il était du type unsigned char (et donc toute représentation d’object possible est valide et a une valeur différente).

Je pense que vous pensez que la valeur renvoyée par strcmp devrait d’une certaine manière dépendre des chaînes d’entrée qui lui sont transmises d’une manière qui n’est pas définie par la spécification de la fonction. Ce n’est pas correct Voir par exemple la définition POSIX:

http://pubs.opengroup.org/onlinepubs/009695399/functions/strcmp.html

À la fin, strcmp () doit renvoyer un entier supérieur, égal ou inférieur à 0, si la chaîne pointée par s1 est supérieure, égale ou inférieure à la chaîne pointée par s2, respectivement.

C’est exactement ce que vous voyez. L’implémentation n’a pas besoin de garantir la valeur de retour exacte , mais uniquement inférieure à zéro, égale à zéro ou supérieure à zéro, le cas échéant.