J'essaie de réimplémenter la strcasecmp
fonction en C et j'ai remarqué ce qui semble être une incohérence dans le processus de comparaison.
De man strcmp
La fonction strcmp () compare les deux chaînes s1 et s2. Les paramètres régionaux ne sont pas pris en compte (pour une comparaison tenant compte des paramètres régionaux, voir strcoll (3)). Il retourne un entier inférieur, égal ou supérieur à zéro si s1 se révèle, respectivement, être inférieur à, correspondre ou être supérieur à s2.
De man strcasecmp
La fonction strcasecmp () effectue une comparaison octet par octet des chaînes s1 et s2, en ignorant la casse des caractères. Il retourne un entier inférieur, égal ou supérieur à zéro si s1 se révèle, respectivement, être inférieur à, correspondre ou être supérieur à s2.
int strcmp(const char *s1, const char *s2);
int strcasecmp(const char *s1, const char *s2);
Étant donné ces informations, je ne comprends pas le résultat du code suivant:
#include <stdio.h>
#include <string.h>
int main()
{
// ASCII values
// 'A' = 65
// '_' = 95
// 'a' = 97
printf("%i\n", strcmp("A", "_"));
printf("%i\n", strcmp("a", "_"));
printf("%i\n", strcasecmp("A", "_"));
printf("%i\n", strcasecmp("a", "_"));
return 0;
}
Sortie:
-1 # "A" is less than "_"
1 # "a" is more than "_"
2 # "A" is more than "_" with strcasecmp ???
2 # "a" is more than "_" with strcasecmp
Il semble que, si le caractère actuel dans s1
est une lettre, il est toujours converti en minuscules, que le caractère actuel dans s2
soit une lettre ou non.
Quelqu'un peut-il expliquer ce comportement? Les première et troisième lignes ne devraient-elles pas être identiques?
Merci d'avance!
PS:
J'utilise gcc 9.2.0
sur Manjaro.
De plus, lorsque je compile avec le -fno-builtin
drapeau, je reçois à la place:
-30
2
2
2
Je suppose que c'est parce que le programme n'utilise pas les fonctions optimisées de gcc, mais la question demeure.
printf("%i\n", strcasecmp("a", "_"));
cela devrait probablement avoir le même résultat queprintf("%i\n", strcasecmp("A", "_"));
Mais cela signifie que l' un de ces deux appels ne respectant pas la casse va être en désaccord avec son homologue sensible à la casse.strcasecmp
vous faites référence ne soit pas exacte. Plus de détails dans les réponses votées.A < _ && a > _ && A == a
causerait tellement de problèmes.unsigned char
. C17 / 18 "Gestion des chaînes <string.h>" -> "Pour toutes les fonctions du présent paragraphe, chaque caractère doit être interprété comme s'il avait le typeunsigned char
". Cela fait une différence une fois que leschar
valeurs sont en dehors de la plage ASCII 0-127.Réponses:
Le comportement est correct.
Selon la
str\[n\]casecmp()
spécification POSIX :Cela fait également partie de la section NOTES de la page de manuel Linux :
Pourquoi?
Comme @HansOlsson l'a souligné dans sa réponse , faire des comparaisons insensibles à la casse entre seulement des lettres et permettre à toutes les autres comparaisons d'avoir leurs résultats "naturels" comme cela le
strcmp()
ferait romprait le tri.Si
'A' == 'a'
(la définition d'une comparaison insensible à la casse) alors'_' > 'A'
et'_' < 'a'
(les résultats "naturels" dans le jeu de caractères ASCII) ne peuvent pas être tous les deux vrais.la source
'_' > 'A' && '_' < 'a'
; ne semble pas être le meilleur exemple.'a' == 'A'
par définition , si vous faites une comparaison entre les valeurs "naturelles" de'a'
,'A'
et'_
', vous ne pouvez pas faire une comparaison insensible à la casse entre'A'
et'a'
pour obtenir l'égalité et obtenir des résultats de tri cohérents.'a'
,'A'
et'_'
, en parcourant les 6 ordres d'insertion dans l'arbre, et en comparant les résultats des "lettres toujours minuscules" spécifiées à la proposition de la question "ne convertir que les lettres" quand c'est une comparaison de lettre à lettre ". Par exemple, en utilisant ce dernier algorithme et en commençant par'_'
,'a'
et vous vous'A'
retrouvez sur les côtés opposés de l'arbre, mais ils sont définis comme égaux. L'algorithme «convertir uniquement les lettres en minuscules dans les comparaisons lettre à lettre» est rompu et ces 3 caractères le montrent.'_' > 'A'
et'_' < 'a'
ne peut pas être vrai tous les deux" sans nous dire pourquoi nous aurions jamais pensé que ce serait le cas. (C'est une tâche pour le répondeur, pas pour un million de lecteurs.)D'autres liens, http://man7.org/linux/man-pages/man3/strcasecmp.3p.html pour strcasecmp, indiquent que la conversion en minuscules est le comportement correct (au moins dans les paramètres régionaux POSIX).
La raison de ce comportement est que si vous utilisez strcasecmp pour trier un tableau de chaînes, il est nécessaire d'obtenir des résultats raisonnables.
Sinon, si vous essayez de trier "A", "C", "_", "b" en utilisant par exemple qsort, le résultat dépendra de l'ordre des comparaisons.
la source
C'est exact - et c'est ce que la
strcasecmp()
fonction devrait faire! Il s'agit d'unePOSIX
fonction, plutôt que d'une partie de laC
norme, mais, à partir de " The Open Group Base Specifications, Issue 6 ":Par ailleurs, ce comportement concerne également la
_stricmp()
fonction (telle qu'utilisée dans Visual Studio / MSCV):la source
Le code décimal ASCII
A
est65
pour_
est95
eta
est97
, doncstrcmp()
il fait ce qu'il est supposé faire. Lexicographiquement parlant_
est alors plus petita
et plus grand queA
.strcasecmp()
sera considéréA
comme étanta
*, et comme ila
est plus grand que_
la sortie est également correct.* La norme POSIX.1-2008 dit de ces fonctions (strcasecmp () et strncasecmp ()):
Source: http://man7.org/linux/man-pages/man3/strcasecmp.3.html
la source
A
c'est "plus grand" que_
lors d'une comparaison insensible à la casse, et se demande pourquoi le résultat n'est pas le même que lors d'une comparaison sensible à la casse.Since
strcasecmp () `est insensible à la casse, elle considérera A comme étant a` est une déduction non valide. Une routine insensible à la casse pourrait traiter toutes les lettres majuscules comme s'il s'agissait de lettres minuscules, pourrait traiter toutes les lettres minuscules comme s'il s'agissait de lettres majuscules, ou pourrait traiter chaque lettre majuscule comme égale à sa lettre minuscule correspondante et vice-versa, mais toujours les comparer aux caractères non alphabétiques avec leurs valeurs brutes. Cette réponse n'indique pas de raison pour préférer l'une de ces possibilités (la raison correcte pour laquelle la documentation dit d'utiliser des minuscules).