Estoy tratando de reimplementar la strcasecmp
función en C y noté lo que parece ser una inconsistencia en el proceso de comparación.
Desde man strcmp
La función strcmp () compara las dos cadenas s1 y s2. La configuración regional no se tiene en cuenta (para una comparación de configuración regional, consulte strcoll (3)). Devuelve un número entero menor, igual o mayor que cero si se encuentra s1, respectivamente, menor que, para que coincida o mayor que s2.
Desde man strcasecmp
La función strcasecmp () realiza una comparación byte por byte de las cadenas s1 y s2, ignorando el caso de los caracteres. Devuelve un número entero menor, igual o mayor que cero si se encuentra s1, respectivamente, menor que, para que coincida o mayor que s2.
int strcmp(const char *s1, const char *s2);
int strcasecmp(const char *s1, const char *s2);
Dada esta información, no entiendo el resultado del siguiente código:
#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;
}
Ouput:
-1 # "A" is less than "_"
1 # "a" is more than "_"
2 # "A" is more than "_" with strcasecmp ???
2 # "a" is more than "_" with strcasecmp
Parece que, si el carácter actual en s1
es una letra, siempre se convierte en minúsculas, independientemente de si el carácter actual en s2
es una letra o no.
¿Alguien puede explicar este comportamiento? ¿No deberían ser idénticas las líneas primera y tercera?
¡Gracias de antemano!
PD:
estoy usando gcc 9.2.0
en Manjaro.
Además, cuando compilo con la -fno-builtin
bandera me sale en su lugar:
-30
2
2
2
Supongo que es porque el programa no usa las funciones optimizadas de gcc, pero la pregunta sigue siendo.
printf("%i\n", strcasecmp("a", "_"));
presumiblemente, esto debería tener el mismo resultado queprintf("%i\n", strcasecmp("A", "_"));
Pero eso significa que una de estas dos llamadas que no distinguen entre mayúsculas y minúsculas no estará de acuerdo con su contraparte sensible a mayúsculas y minúsculas.strcasecmp
que te refieres no es precisa. Más detalles en las respuestas votadas.A < _ && a > _ && A == a
causaría tantos problemas.unsigned char
. C17 / 18 "Manejo de cadenas <string.h>" -> "Para todas las funciones en esta subcláusula, cada carácter se interpretará como si tuviera el tipounsigned char
". Esto hace la diferencia una vez que loschar
valores están fuera del rango ASCII 0-127.Respuestas:
El comportamiento es correcto.
Por la
str\[n\]casecmp()
especificación POSIX :Eso también es parte de la sección NOTAS de la página de manual de Linux :
¿Por qué?
Como @HansOlsson señaló en su respuesta , hacer comparaciones que no distingan entre mayúsculas y minúsculas entre letras y permitir que todas las demás comparaciones tengan sus resultados "naturales" tal como se hace
strcmp()
, interrumpiría la clasificación.Si
'A' == 'a'
(la definición de una comparación entre mayúsculas y minúsculas), entonces'_' > 'A'
y'_' < 'a'
(los resultados "naturales" en el conjunto de caracteres ASCII) no pueden ser ambos verdaderos.fuente
'_' > 'A' && '_' < 'a'
; No parece ser el mejor ejemplo.'a' == 'A'
, por definición , si lo hace una comparación entre los valores "naturales" de'a'
,'A'
y'_
', que no se puede hacer una comparación entre mayúsculas y minúsculas entre'A'
y'a'
para conseguir la igualdad y obtener ordenar resultados consistentes.'a'
,'A'
y'_'
, pasando por los 6 órdenes de inserción en el árbol, y comparando los resultados de las "letras minúsculas" como se especifica con las "letras convertidas únicas" de la pregunta cuando se trata de una comparación letra a letra ". Por ejemplo, usar el último algoritmo y comenzar con'_'
,'a'
y'A'
terminar en lados opuestos del árbol, pero se definen como iguales. El algoritmo "solo convertir letras a minúsculas en las comparaciones letra-letra" está roto y esos 3 caracteres lo demuestran.'_' > 'A'
y'_' < 'a'
no puede ser verdad" sin decirnos por qué deberíamos haber pensado que sería. (Esa es una tarea para el que responde, no para uno de los millones de lectores.)Otros enlaces, http://man7.org/linux/man-pages/man3/strcasecmp.3p.html para strcasecmp dicen que la conversión a minúsculas es el comportamiento correcto (al menos en la ubicación POSIX).
La razón de ese comportamiento es que si usa strcasecmp para ordenar una serie de cadenas, es necesario obtener resultados razonables.
De lo contrario, si intenta ordenar "A", "C", "_", "b" utilizando, por ejemplo, qsort, el resultado dependerá del orden de las comparaciones.
fuente
Eso es correcto, ¡y es lo
strcasecmp()
que debería hacer la función ! Es unaPOSIX
función, más que parte delC
Estándar, pero, de " The Open Group Base Especificaciones, Issue 6 ":Por cierto, este comportamiento también es pertinente para la
_stricmp()
función (como se usa en Visual Studio / MSCV):fuente
El código decimal ASCII para
A
es65
para_
es95
y paraa
es97
, porstrcmp()
lo que está haciendo lo que se supone que debe hacer. Lexicográficamente hablando_
es más pequeño entoncesa
y más grande queA
.strcasecmp()
se consideraráA
comoa
*, y dado quea
es más grande que_
la salida, también es correcta.* El estándar POSIX.1-2008 dice de estas funciones (strcasecmp () y strncasecmp ()):
Fuente: http://man7.org/linux/man-pages/man3/strcasecmp.3.html
fuente
A
es "más grande" que_
cuando se compara entre mayúsculas y minúsculas, y se pregunta por qué el resultado no es el mismo que cuando se compara entre mayúsculas y minúsculas.Since
strcasecmp () `no distingue entre mayúsculas y minúsculas, considerará que A como a` es una deducción no válida. Una rutina que no distingue entre mayúsculas y minúsculas podría tratar todas las letras mayúsculas como si fueran letras minúsculas, podría tratar todas las letras minúsculas como si fueran letras mayúsculas o podría tratar cada letra mayúscula como igual a su letra minúscula correspondiente y viceversa, pero aún así compararlas a caracteres que no son letras con sus valores sin formato. Esta respuesta no indica una razón para preferir ninguna de esas posibilidades (la razón correcta es que la documentación dice que use minúsculas).