strcmp와 한글

spacelee의 이미지

strcmp("abc","안녕하세요") 의 결과가 -1 입니다.
즉, abc를 8bit가 on이된 CJK 문자보다 작게 판단을 하네요.

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

에서 아규먼트가 unsigned가 아니므로,
8bit on된 문자는 음수로 판단해서
위 결과는 양수가 나올줄 알았는데...ㅡ,.ㅡ

이 부분에 대해 어떤 식으로 동작한다고 이해를 해야 되나여.
혹시 posix 표준에서 어떻게 동작한다고 정의된 건 있는지
아시는 분 좀 알려주세요.

C를 오래했다고 생각했는데, 이런 기초적인 문제에서 헷갈리니
혼돈스럽네여...ㅜㅜ

hyperhidrosis의 이미지

표준의 정의는 모르겠지만, 구현은 컴파일러 마다 다르더군요

어떤 경우는 unsigned 로 비교하고 어떤 경우는 signed 로 비교하더군요..

컴파일러의 c 라이브러리 만든놈 맘대로 입니다.

익명 사용자의 이미지

wstrcmp를 써야 하는거 아닐까요? 이것은 로케일과 관련있습니다.

doldori의 이미지

strcmp()의 결과가 1이 되리라고 기대하는 데는 다음과 같은 가정이 깔려 있습니다.

1. char형은 부호가 있다.
2. "안녕하세요"라는 문자열은 음수로 저장된다.

spacelee님이 실행하신 환경에서는 이 가정들이 만족한다면 결과가 -1인 이유는
strcmp()의 구현과 관련된 문제로 보입니다. strcmp() 내부에서 unsigned char로
변환한다면 그럴 수 있죠.
문자열을 비교하기 위한 함수로 strcmp() 외에 strcoll()도 있습니다. 두 함수의
차이는 strcoll()이 현재 설정된 locale의 영향을 받는다는 것입니다.

setlocale(LC_COLLATE, "ko_KR"); // or "Korean" on Win32
strcoll("abcd", "안녕하세요");

그런데 locale이란 것도 환경에 의존하는 부분이 많아서 strcoll()의 결과도 환경에
따라 달라질 수 있다는 점은 주의하셔야 합니다.
spacelee의 이미지

doldori wrote:
strcmp()의 결과가 1이 되리라고 기대하는 데는 다음과 같은 가정이 깔려 있습니다.

1. char형은 부호가 있다.
2. "안녕하세요"라는 문자열은 음수로 저장된다.

spacelee님이 실행하신 환경에서는 이 가정들이 만족한다면 결과가 -1인 이유는
strcmp()의 구현과 관련된 문제로 보입니다. strcmp() 내부에서 unsigned char로
변환한다면 그럴 수 있죠.
문자열을 비교하기 위한 함수로 strcmp() 외에 strcoll()도 있습니다. 두 함수의
차이는 strcoll()이 현재 설정된 locale의 영향을 받는다는 것입니다.

setlocale(LC_COLLATE, "ko_KR"); // or "Korean" on Win32
strcoll("abcd", "안녕하세요");

그런데 locale이란 것도 환경에 의존하는 부분이 많아서 strcoll()의 결과도 환경에
따라 달라질 수 있다는 점은 주의하셔야 합니다.

앗 감사...!!!
그런 함수 얼핏 보기만 했지 뭔지 모르고 있었는데..^^;;
감사합니당. 윗분두요.~^^

근데 컴파일러마다 다르면 이식할때 그런 부분도 고민을 해야되겠군요.
그래도 gcc라면 시스템마다 모두 동작이 같겠죠?

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

익명 사용자의 이미지

strcmp 같은 함수는 standard C library에 속한 함수입니다.

이 라이브러리는 플랫폼마다 다르기 때문에 gcc를 사용하더라도 플랫폼 마다 다른 결과가 나올 수 있습니다.

물론 gnu C library를 설치하고 그것을 이용한다면 같은 결과가 나오겠지요.

하지만 gcc가 깔린다고 반드시 gnu C library가 깔리는 것은 아니기 때문에 platform에 따라서 달라진다고 보셔야 할 것 같습니다.

예를 들어서 솔라리스 같은 경우 기본으로 제공되는 gcc에서는 솔라리스에 존재하는 C library를 사용합니다.

doldori의 이미지

spacelee wrote:
그래도 gcc라면 시스템마다 모두 동작이 같겠죠?

그렇지 않습니다. locale이 컴파일러보다 플랫폼에 의존하는 부분이 많기 때문입니다.
locale과 관련된 이식성 문제는 저도 경험이 없어도 도움을 드리기는 힘들겠군요.
spacelee의 이미지

그런데 이 부분에 대해서 posix에서는 명시적으로 정한 내용이 없나여?
있는데 안지키는건지 아예 없는건지 모르겠네여.

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

IsExist의 이미지

아마도 내부 코드는 이럴겁니다.

    if (s1[i] != s2[i]) return (s1[i] - s2[i]);

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

hyperhidrosis의 이미지

IsExist wrote:
아마도 내부 코드는 이럴겁니다.

    if (s1[i] != s2[i]) return (s1[i] - s2[i]);

함수 정의는 양수, 음수라고 되어 있지만
대부분의 구현은 -1, 0, -1 인것으로 보아 저렇게 구현되어
있지는 않을껍니다.

( 더군다나 성능문제가 있기 때문에 array 를 써서 구현하지는 않습니다. )

참고로 msvcrt 의 소스를 보니까
알고리즘은

int strcmp ( src , dst )                          
        unsigned char *src;                       
        unsigned char *dst;                       
{                                                 
        int ret = 0 ;                             
                                                  
        while( ! (ret = *src - *dst) && *dst)     
                ++src, ++dst;                     
                                                  
        if ( ret < 0 )                            
                ret = -1 ;                        
        else if ( ret > 0 )                       
                ret = 1 ;                         
                                                  
        return( ret );                            
}                                                 

라고 되어 있고 실지 구현은 어셈으로 되어 있네요

[/code]

mykhs7200의 이미지

"8bit가 on" 되었다는 표현이 애매한데
아마 8번째 비트가 1인 경우를 말하는 것이겠지!!!

그리고 문자열의 비교에서는 음수 양수를 따지지 않음

아마 결과는 영문 대소문자는 무조건 127 이하이고
한글은 얼마부터 시작하는 지 정확하게는 모르지만
127보다 클거야 그래서 앞 숫자에서 뒤 숫자를 빼니
음수가 나오며

요즘 리눅스에서는 단지 1, 0, -1로만 표현하는 것 같다.

전웅의 이미지

POSIX 까지 갈 필요도 없습니다. strcmp() 는 C 표준이 행동을 정의한 함수
입니다.

일반적인 환경 (8비트 크기 바이트, padding 없음 등등) 을 고려했을 때
사용하시는 환경에서 한글을 구성하는 첫 바이트의 최상위 비트가 항상 1
이라고 하면, strcmp() 의 결과는 얻으신대로 나와야 합니다 - 그렇게
나오지 않는 구현체는 잘못된 구현체입니다.

str*() 함수들이 비록 매개변수 형이 char * 로 되어 있어도 각 문자
접근은 unsigned char * 로 이루어지도록 정의되어 있습니다. 즉, 솔직
담백하게 구현하자면, char * 로 받아서 unsigned * 로 변환한 후에 접근
합니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

spacelee의 이미지

전웅 wrote:
POSIX 까지 갈 필요도 없습니다. strcmp() 는 C 표준이 행동을 정의한 함수
입니다.

일반적인 환경 (8비트 크기 바이트, padding 없음 등등) 을 고려했을 때
사용하시는 환경에서 한글을 구성하는 첫 바이트의 최상위 비트가 항상 1
이라고 하면, strcmp() 의 결과는 얻으신대로 나와야 합니다 - 그렇게
나오지 않는 구현체는 잘못된 구현체입니다.

str*() 함수들이 비록 매개변수 형이 char * 로 되어 있어도 각 문자
접근은 unsigned char * 로 이루어지도록 정의되어 있습니다. 즉, 솔직
담백하게 구현하자면, char * 로 받아서 unsigned * 로 변환한 후에 접근
합니다.

감솨~~~~~^^

영광입니다. 전웅님이 답변을 직접 해주시니..^^;;

역시 전웅님이시네요 명쾌하게 알려주셔서 감솨감솨~^^

권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -

doldori의 이미지

전웅 wrote:
str*() 함수들이 비록 매개변수 형이 char * 로 되어 있어도 각 문자
접근은 unsigned char * 로 이루어지도록 정의되어 있습니다. 즉, 솔직
담백하게 구현하자면, char * 로 받아서 unsigned * 로 변환한 후에 접근
합니다.

이 말씀은 표준에서 그렇게 정의되어 있다는 뜻인가요?
제가 관련 문구를 찾지 못해서 그러는데, 그 부분을 짚어주시면 고맙겠습니다.
전웅의 이미지

doldori wrote:
전웅 wrote:
str*() 함수들이 비록 매개변수 형이 char * 로 되어 있어도 각 문자
접근은 unsigned char * 로 이루어지도록 정의되어 있습니다. 즉, 솔직
담백하게 구현하자면, char * 로 받아서 unsigned * 로 변환한 후에 접근
합니다.

이 말씀은 표준에서 그렇게 정의되어 있다는 뜻인가요?
제가 관련 문구를 찾지 못해서 그러는데, 그 부분을 짚어주시면 고맙겠습니다.

넵. C90에서는 불분명했는데 DR을 거쳐서 C99에는 명시되었습니다.

C99 7.21.1p3 wrote:
For all functions in this subclause, each character shall be
interpreted as if it had the type unsigned char (and therefore every
possible object representation is valid and has a different value).

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

doldori의 이미지

전웅 wrote:
넵. C90에서는 불분명했는데 DR을 거쳐서 C99에는 명시되었습니다.

C99 7.21.1p3 wrote:
For all functions in this subclause, each character shall be
interpreted as if it had the type unsigned char (and therefore every
possible object representation is valid and has a different value).

감사합니다. 그게 TC에 추가된 것이어서 제가 못찾았던 거로군요. T.T
전웅의 이미지

doldori wrote:
감사합니다. 그게 TC에 추가된 것이어서 제가 못찾았던 거로군요. T.T

아, 그러고보니 TC 가 배제된 C99에도 첨가되지 않은 부분이군요. 전 C90
TC에서 수정된 사안이라 생각했는데 잘못 기억하고 있었군요.

위원회 문서 n1124.pdf 를 보시면 TC가 모두 적용된 C99 문서를 확인하실
수 있습니다. 공식적으로 publish 된 표준은 아니지만 TC 내용이 모두
포함되어 있으므로 reference 로 사용하시기에 편리할 겁니다.

그럼...

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.