[c] strcasecmp 알고리즘에 결함이 있습니까?

strcasecmpC 에서 함수 를 다시 구현하려고하는데 비교 과정에서 불일치하는 것으로 나타났습니다.

에서 man strcmp

strcmp () 함수는 두 문자열 s1과 s2를 비교합니다. 로케일은 고려되지 않습니다 (로케일 인식 비교는 strcoll (3) 참조). s1이 각각 s2보다 작거나 일치하거나 s2보다 크면 0보다 작거나 같거나 0보다 큰 정수를 리턴합니다.

에서 man strcasecmp

strcasecmp () 함수는 문자열의 경우를 무시하고 문자열 s1 및 s2를 바이트 단위로 비교합니다. s1이 각각 s2보다 작거나 일치하거나 s2보다 크면 0보다 작거나 같거나 0보다 큰 정수를 리턴합니다.

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

이 정보가 주어지면 다음 코드의 결과를 이해하지 못합니다.

#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;
}

출력 :

-1  # "A" is less than "_"
1   # "a" is more than "_"
2   # "A" is more than "_" with strcasecmp ???
2   # "a" is more than "_" with strcasecmp

현재 문자 s1가 문자이면 현재 문자 가 문자 인지 여부에 관계없이 항상 소문자로 변환됩니다 s2.

누군가이 행동을 설명 할 수 있습니까? 첫 번째 줄과 세 번째 줄이 동일하지 않아야합니까?

미리 감사드립니다!

추신 :
저는 gcc 9.2.0Manjaro를 사용 하고 있습니다.
또한 -fno-builtin플래그로 컴파일 하면 대신 얻을 수 있습니다.

-30
2
2
2

프로그램이 gcc의 최적화 된 기능을 사용하지 않기 때문이지만 질문은 남아 있습니다.



답변

동작이 정확합니다.

는 POSIX의 str\[n\]casecmp()사양 :

LC_CTYPE사용되는 로케일 의 카테고리가 POSIX 로케일의 것이라면,이 함수는 문자열이 소문자로 변환 된 다음 바이트 비교가 수행 된 것처럼 작동합니다. 그렇지 않으면 결과가 지정되지 않습니다.

그것도의 일부입니다 NOTES의 리눅스 man 페이지의 섹션 :

POSIX.1-2008 표준은 다음 기능을 말합니다.

사용되는 로케일의 LC_CTYPE 범주가 POSIX 로케일에서 온 경우,이 함수는 문자열이 소문자로 변환 된 후 바이트 비교가 수행 된 것처럼 작동합니다. 그렇지 않으면 결과가 지정되지 않습니다.

왜?

@HansOlsson이 그의 답변에서 지적했듯이 문자 만 대소 문자를 구분하지 않고 비교하면 다른 모든 비교에서 “자연스러운”결과를 얻을 수 있으므로 strcmp()정렬이 어려워 집니다 .

경우 'A' == 'a'(대소 문자를 구분하지 않는 비교의 정의는) 다음 '_' > 'A''_' < 'a'(ASCII 문자 세트의 “자연”결과는) 모두 사실이 될 수 없습니다.


답변

strcasecmp에 대한 다른 링크 http://man7.org/linux/man-pages/man3/strcasecmp.3p.html 에 따르면 소문자로 변환하는 것이 올바른 동작이라고합니다 (적어도 POSIX 로켈에서).

그 동작의 이유는 strcasecmp를 사용하여 문자열 배열을 정렬하면 합리적인 결과를 얻는 것이 필요하기 때문입니다.

그렇지 않으면 예를 들어 qsort를 사용하여 “A”, “C”, “_”, “b”를 정렬하려고하면 결과는 비교 순서에 따라 달라집니다.


답변

s1의 현재 문자가 문자이면 s2의 현재 문자가 문자인지 여부에 관계없이 항상 소문자로 변환됩니다.

맞습니다. 그리고 strcasecmp()함수 가해야 할 일입니다! 이 POSIX기능은 C표준의 일부가 아니라 ” 공개 그룹 기본 사양, 문제 6 “의 기능입니다.

POSIX 로케일에서 strcasecmp () 및 strncasecmp ()는 문자열이 소문자로 변환 된 후 바이트 비교가 수행 된 것처럼 동작합니다. 다른 로케일에서는 결과가 지정되지 않습니다.

또한이 동작은 _stricmp()Visual Studio / MSCV에서 사용되는 함수와 도 관련이 있습니다 .

_stricmp 함수는 일반적으로 각 문자를 소문자로 변환 한 후 string1과 string2를 비교하고 관계를 나타내는 값을 반환합니다.


답변

대한 ASCII 진수 코드 A입니다 65에 대한 _것입니다 95및 위해 a이다 97, 그래서 strcmp()할 가정 해 무엇을하고있어. 사 전적으로 말하기 _는 다음보다 작고 a큽니다 A.

strcasecmp()* A로 간주 되며 출력이 크기보다 크므로 정확합니다.aa_

* POSIX.1-2008 표준에 따르면 이러한 함수 (strcasecmp () 및 strncasecmp ())에 대해 설명합니다.

사용되는 로케일의 LC_CTYPE 범주가 POSIX 로케일에서 온 경우,이 함수는 문자열이 소문자로 변환 된 후 바이트 비교가 수행 된 것처럼 작동합니다. 그렇지 않으면 결과가 지정되지 않습니다.

출처 : http://man7.org/linux/man-pages/man3/strcasecmp.3.html


답변