Estou tentando reimplementar a strcasecmp
função em C e notei o que parece ser uma inconsistência no processo de comparação.
De man strcmp
A função strcmp () compara as duas seqüências s1 e s2. O código do idioma não é levado em consideração (para uma comparação com reconhecimento do código do idioma, consulte strcoll (3)). Retorna um número inteiro menor que, igual a ou maior que zero se s1 for encontrado, respectivamente, menor que, para corresponder ou maior que s2.
De man strcasecmp
A função strcasecmp () executa uma comparação de bytes por bytes das seqüências s1 e s2, ignorando o caso dos caracteres. Retorna um número inteiro menor que, igual a ou maior que zero se s1 for encontrado, respectivamente, menor que, para corresponder ou maior que s2.
int strcmp(const char *s1, const char *s2);
int strcasecmp(const char *s1, const char *s2);
Dada essa informação, não entendo o resultado do seguinte 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, se o caractere atual em s1
for uma letra, ele sempre será convertido em minúsculas, independentemente de o caractere atual s2
ser uma letra ou não.
Alguém pode explicar esse comportamento? A primeira e a terceira linhas não deveriam ser idênticas?
Agradeço antecipadamente!
PS:
Estou usando o gcc 9.2.0
Manjaro.
Além disso, quando compilo com a -fno-builtin
bandeira, recebo:
-30
2
2
2
Eu acho que é porque o programa não usa as funções otimizadas do gcc, mas a questão permanece.
printf("%i\n", strcasecmp("a", "_"));
presumivelmente, isso deve ter o mesmo resultado queprintf("%i\n", strcasecmp("A", "_"));
Mas isso significa que uma dessas duas chamadas que não diferenciam maiúsculas de minúsculas vai discordar de sua contraparte que diferencia maiúsculas de minúsculas.strcasecmp
você está se referindo não é precisa. Mais detalhes nas respostas votadas.A < _ && a > _ && A == a
causaria muitos problemas.unsigned char
. C17 / 18 "Tratamento de strings <string.h>" -> "Para todas as funções desta subcláusula, cada caractere deve ser interpretado como se tivesse o tipounsigned char
". Isso faz diferença quando oschar
valores estão fora do intervalo ASCII de 0 a 127.Respostas:
O comportamento está correto.
De acordo com a
str\[n\]casecmp()
especificação POSIX :Isso também faz parte da NOTAS seção da página de homem Linux :
Por quê?
Como o @HansOlsson apontou em sua resposta , fazer comparações sem distinção entre maiúsculas e minúsculas entre apenas letras e permitir que todas as outras comparações tenham seus resultados "naturais", como foi feito
strcmp()
, quebraria a classificação.Se
'A' == 'a'
(a definição de uma comparação sem distinção entre maiúsculas e minúsculas)'_' > 'A'
e'_' < 'a'
( e os resultados "naturais" no conjunto de caracteres ASCII) não puderem ser verdadeiros.fonte
'_' > 'A' && '_' < 'a'
; não parece ser o melhor exemplo.'a' == 'A'
por definição , se você fizer uma comparação entre os valores "naturais" de'a'
,'A'
e'_
', não poderá fazer uma comparação sem distinção entre maiúsculas e minúsculas entre'A'
e'a'
para obter igualdade e obter resultados de classificação consistentes.'a'
,'A'
e'_'
, passando por todos os 6 ordens de inserção na árvore, e comparando os resultados das as-especificadas "letras sempre minúscula" para a questão da proposta "só converter letras quando é uma comparação letra a letra ". Por exemplo, usando o último algoritmo e começando com'_'
,'a'
e'A'
acabe em lados opostos da árvore, no entanto, eles são definidos como iguais. O algoritmo "apenas converter letras para minúsculas nas comparações letra-letra" é quebrado e esses três caracteres mostram isso.'_' > 'A'
e'_' < 'a'
não podem ser verdadeiras" sem nos dizer por que deveríamos ter pensado que seria. (Essa é uma tarefa para quem responde, não para um milhão de leitores.)Outros links, http://man7.org/linux/man-pages/man3/strcasecmp.3p.html para strcasecmp, dizem que a conversão para minúsculas é o comportamento correto (pelo menos no código do idioma POSIX).
A razão para esse comportamento é que, se você usar strcasecmp para classificar uma matriz de seqüências, é necessário obter resultados razoáveis.
Caso contrário, se você tentar classificar "A", "C", "_", "b" usando, por exemplo, qsort, o resultado dependerá da ordem das comparações.
fonte
Está correto - e é o que a
strcasecmp()
função deve fazer! É umaPOSIX
função, e não parte doC
Padrão, mas das " Especificações de Base do Grupo Aberto, Edição 6 ":Aliás, esse comportamento também é relevante para a
_stricmp()
função (conforme usado no Visual Studio / MSCV):fonte
O código decimal ASCII para
A
é65
para_
é95
e paraa
é97
, entãostrcmp()
está fazendo o que deveria fazer. Lexicograficamente falando_
é menora
e maior queA
.strcasecmp()
consideraráA
como sendoa
* e, comoa
é maior que_
a saída, também está correto.* O padrão POSIX.1-2008 diz sobre essas funções (strcasecmp () e strncasecmp ()):
Fonte: http://man7.org/linux/man-pages/man3/strcasecmp.3.html
fonte
A
é "maior" do que_
ao comparar sem distinção entre maiúsculas e minúsculas e se pergunta por que o resultado não é o mesmo que quando se compara com distinção entre maiúsculas e minúsculas.Since
strcasecmp () `não faz distinção entre maiúsculas e minúsculas; considerará A como sendo um` é uma dedução inválida. Uma rotina que não diferencia maiúsculas de minúsculas pode tratar todas as letras maiúsculas como se fossem minúsculas, tratar todas as letras minúsculas como se fossem letras maiúsculas ou tratar cada letra maiúscula como igual à sua letra minúscula correspondente e vice-versa, mas ainda compará-las para caracteres sem letra com seus valores brutos. Esta resposta não indica um motivo para preferir nenhuma dessas possibilidades (o motivo correto pelo qual a documentação diz que usa letras minúsculas).