티스토리 뷰

Computer/C

멀티바이트와 유니코드

jamezc 2013. 7. 27. 00:44


오늘 울 회사 과장님께서 나에게 VC++ 에서 프로젝트 기본값 -> 문자 집합을 멀티바이트로 하는지 물어보셨다.

난 당연히 멀티바이트로 쓴다고 말씀드렸다.

그리고 왜 물어보시냐고 여쭤보니깐 문자 집합을 멀티 바이트로 해놓으면 나중에 ANSI -> 유니코드, 유니코드 -> ANSI로 변환할 때 문제가 없기 때문이라고 말씀하셨다.

과장님께서 클라이언트에서 다국어 처리를 할 때 입력은 ANSI로 받고, ANSI로 받은 것을 내부에서 유니코드로 변경하고, 이것을 출력할 때나 서버로 전송할 때는 다시 ANSI로 변경한다고 하셨다.

왜 그렇게 하냐고 여쭤보니.. ANSI로 다국어 문자를 받으면 처리하기가 애매한 경우가 많은데 이것을 유니코드로 변경해서 필터링이나 짤라주기 등을 해주고, 이것을 다시 ANSI로 변경하면 괜찮다는 것이다.

음.. 듣고보니 그런거 같다.

ANSI로는 다국어 처리를 하기란 상당히 까다로울 거 같은데.. 어떤 나라는 글자 하나가 1BYTE고, 어떤 나라는 글자 하나가 2, 3, 4, 5, 6 이렇게 다양한데 이런걸 다 ANSI로 1BYTE씩 파씽해서 처리하기가 상당히 까다로운거 같다. 유니코드로 변경하면 글자가 몇 바이트인지 신경 쓸 필요가 없으니깐 좋은거 같다.


퍼옴 : http://blog.daum.net/ohkuetai/5993663



비슷한듯하면서 헷갈릴수 있는데..

유니코드는 분명 모든 문자에 대해 동일한 코드체계로 가져간다는 것이다.


멀티바이트는 일반적으로 안시코드(1바이트 문자셋)로 표기되지 않는 문자셋을 표기하기 위해 2개이상의 바이트를 사용한거를 말하는 것이다. .. 그래서 1바이트문자와 2바이트문자가 같이 등장하게 된다.


VISUAL C++같은데서는 _MBCS, _UNICODE 정의와 T-매크로로 두가지 버전에 대해 코드레벨에서 호환되도록 작성할 수 있게 해준다.


그렇지만! 분명 멀티바이트/유니코드는 그 차이를 분명히 알고 써야 한다!!!



최근엔 유니코드로만 해서 _MBCS 처리를 별로 할일이 없긴 하지만, 그래도 멀티바이트 처리를 할땐 그 차이를 알고 조심해야 된다는 것을 강조하고 싶다.


암생각없이 strlen("한글abc") 이라고 하는데.. 이게, _mbstrlen("한글abc")하고, _wcslen(L"한글abc") 하고..3가지 버전이 어떤 값을 뱉어낼지 알아야 한다는 것이다.


assert(strlen("한글abc") == 7); // 7 bytes

assert(_mbstrlen("한글abc") == 5); // 7 bytes

assert(_wcslen(L"한글abc") == 5); // 10 bytes


그나마 _tcslen  이 있긴하지만, 내가 지금 필요한게 byte인지, 글자개수 인지를 정확히 알아야지 제대로 쓸수 있다. (안그럼?? 뻑나겠지. ^^)


..


이제 멀티바이트 사용할 때 유용한 함수들(그래서 여기저기 잘/많이 사용하게 되는)을 보면..

 

int _ismbbtrail( unsigned int c );

int _ismbblead( unsigned int c );

 

같은게 있다..  텍스트편집기를 직접 만드는데, 안시빌드를 한다! 그러면 위의 두 함수 없이 어떻게 backspace/delete 키를 처리할까~ ^^


퍼옴 : http://blog.naver.com/jooyunghan?Redirect=Log&logNo=100004007609



VS 2005 부터는 프로젝트 생성시 기본적으로 유니코드 문자집합을 선택하게 되어 있습니다.
처음엔 속성에서 일일이 멀티 바이트 문자집합으로 바꿔주기도 했지만 곧 그것도 
귀찮더군요. 그래서 현재는 그냥 유니코드에 맞는 코딩을 하고 있습니다. 

윈도우 프로그래밍에선 유니코드나 멀티바이트나 별 차이는 없습니다.

단지 문자나 문자열 앞에 L 또는 TEXT() 매크로를 사용해주는 것만으로도 충분합니다.

그 외엔 운영체제에서 자체 지원하는 

lstrcpy(strcpy)
lstrcmp(strcmp)
lstrcat(strcat)
lstrlen(strlen)

정도만 기억하시면 충분합니다. 

제 경우는 문자열엔 TEXT()를 문자엔 L을 붙여서 코딩하고 있습니다.
둘의 차이는 거의 없기에 어떻게 사용하든 본인의 자유겠죠.
(int 를 제외한 변수를 선언할때도 주의해주셔야 합니다만...
주의할 거래봐야 char 를 TCHAR로 선언해주는 것 정도죠)

하지만 콘솔 프로그래밍으로 넘어가면 이건 그렇게 만만치가 않습니다.

VS 2005 이전에 유니코드를 지원하던 앞에 w가 붙는 함수가
2005로 넘어오면서 w..._s 형으로 다시 바뀐 겁니다. 

_s 형으로 바뀐 건 좋은데 가끔은 받아들이는 인수의 수조차 바뀐 것들이 
있어서 사람을 미치게 합니다. 

예를 들면 

wstrcat_s 
예전엔 2개의 인수만을 받던 strcat 함수가 3개의 인수를 받도록 바껴버린거죠.
물론 여전히 2개의 인수를 받고 유니코드를 지원하는 lstrcat을 사용하면 그만이죠

하지만 어딘가 제가 모르는 저런 식의 함수가 분명 있을 겁니다. 
(콘솔 프로그램의 의미가 거의 바닥을 치는데 이런 예기는 사실 별 의미가 없죠.)

그래도 혹시나 콘솔 프로그램을 작성하시다가 유니코드를 지원하는 함수를 
알 필요가 있을 땐 MSDN을 이용해 보십시오. 영어를 몰라도 
대충보면 어떤 함수를 사용해야 하는지 찾으실 수 있으실 겁니다. 

서론은 여기까지 하고 이 글을 적는 본론으로 들어가죠

제가 콘솔 프로그램을 하나 만들었습니다. 물론, 유니코드를 사용했죠.

그런데 막상 실행해보니 도스창에 한글이 찍히지 않는 겁니다. 
에러 경고 하나도 뜨지 않는데 한글을 안 찍히니 미칠 지경이더군요. 

미친듯이 찾아 본 결과 답을 찾았습니다. 물론, 어째서 그런지는 모릅니다.
전혀요; 

_wsetlocale(LC_ALL,TEXT("Korean"));

이걸 적어줘야 하더군요. 함수 이름만으로는 지역변경 - 한국 쯤 되는군요;

위 함수의 정의는 locale.h 안에 들어 있습니다. 

위 함수를 적어주고 컴파일 하니 한글 출력이 되더군요. 
(망할 유니코드...)

그 외에 이런 경우도 있습니다. 멀티바이트 유니코드 안 따지는 함수들이 
가끔 있습니다. 그 형태 그대로 유지해서 어느 쪽에나 적응가능하죠.

그런데 가끔 이 함수들이 인수로 받아들이는 데이타형이 유니코드에 맞지 않을때가 있습니다.

예를 들면 소켓 프로그래밍의 send,recv 함수 같은 게 있죠
send,recv 함수는 두번째 인수로 (const char*) 형을 받습니다.

이 경우 

TCHAR a[10];

send(socket,(char*)a,......);
//에러

send(socket,(char FAR*)a,......);
//성공

이런 식으로 적어주어야 합니다. recv 역시 마찬가지로 char FAR*
형으로 캐스팅해주면 유니코드 문자열을 넘겨줄 수 있습니다.

지금까지 제가 유니코드를 사용해 코딩하면서 겪은 문제점은 이걸로 대충 다 적었습니다. 

아... 마지막으로 강조해야 할 부분 유니코드는 한 문자가 1바이트가 아니라 2바이트란 거죠.
(멀티바이트는 1바이트 문자셋과 2바이트 문자셋이 섞여 있죠)

유니코드에선 심지어 영어도 2바이트를 차지합니다. 

크게 중요해 보이지 않는 거 같지만 이걸 깜박하면 자신도 모르게 에러를 
내 버릴 수가 있습니다. (특히 메모리 활당 부분)

그럼, 별 의미 없는 글이나마 읽어주셔서 감사합니다.

p.s : wprintf 함수의 경우 유니코드 문자열을 출력할때는 %s 가 아니라 %S를 써야 합니다
안 그럼 알 수 없는 외계어가 출력되죠.

'Computer > C' 카테고리의 다른 글

[C언어] 연산자와 상수  (0) 2015.02.24
scanf 함수 사용시 scanf_s 사용권고하며 오류 발생하는 경우  (0) 2015.02.12
BroadCasting 참고 코드  (0) 2013.07.09
Virtual Key Code  (0) 2013.07.06
키보드 이벤트 처리하기  (0) 2013.07.05
댓글

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음



Total
Today
Yesterday
최근에 달린 댓글