API

멀티바이트 및 유니코드 문자열 길이 구하는 api 사용시 유의점

디버그정 2009. 6. 24. 12:24
멀티바이트는 말그대로 문자 하나의 길이를 다양하게(멀티하게^^) 처리한다는 의미이다.
멀티바이트는 숫자나 영문자나 인용부호 등을 1바이트로 처리하며,
그외 한글이나 중국 글자, 일본글자 등은 2바이트로 표현한다.
1바이트와 2바이트 값을 구분하기 위해 2바이트는 무조건 128(0x80)이후의 값으로 시작할 것이다.
가령 영문 'z'는 0x7a, 한글 '가'는 0xb0,0xa1 값으로 표현된다.
시스템이 문자를 맞딱뜨렸을때 0x80보다 적은 값이면 해당 문자를 z처럼 1바이트로 인식하고
0x80이 넘으면 2바이트 값이므로 다음의 1바이트와 같이 읽어서 의미를 파악할 것이다.


유니코드는 각각의 문자에 유니크한 값을 주어서 모든 문자는 동일한 길이를 지닌다. 현재는 2바이트이다.
세계의 모든 문자를 유니코드로 싸잡으려면 아주 많은 가짓수가 필요할 것이다.
그러므로 1바이트로는 2의 8승 = 256가지밖에 표현안되므로 택도 없다.
현재 2바이트의 길이므로 2의 16승 = 65536가지의 수가 대략적으로 표현가능하다.


위의 두 문자체계 때문에 문자열의 길이를 구하데 헷갈릴 경우가 많다.
lstrlen이나 GetWindowTextLength가 대표적인 api이다.
메모리 용량과 관계되면 조금 골치가 아파진다.
특정 메모리를 할당하고 거기에 문자열을 저장시킬 경우 첨에 몇바이트를 할당할 것인가하는 문제가
그것이다.


참고로 lstrlen의 실체는 lstrlenA와 lstrlenW이다.
(GetWindowTextLength도 GetWindowTextLengthA와 GetWindowTextLengthW로 마찬가지이다.)
lstrlenA는 멀티바이트문자열 길이를 구하는 함수이고, lstrlenW는 유니코드 문자열을 구하는 함수이다.
lstrlen은 실제로 컴파일시 컴파일러가 멀티바이트 컴파일의 경우 lstrlen은 lstrlenA로 변형시키고,
유니코드 컴파일의 경우는 lstrlenW로 변형시킨다..
(디버거로 코드확인해 봄)
물론 어느 컴파일 환경에서도 lstrlenA나 lstrlenW를 직접 쓸수 있다.
여러글들에서도 보면 유니코드 함수를 권장하는데,,,
결국 시스템이 문자열은 유니코드 문자열방식으로 처리하게 되므로 실행속도에서 이득일 것이다.

lstrlenA의 경우 문자하나의 길이는 1일수도 있고 2일수도 있다. 그러므로 구해지는 값은
결국 바이트와 같다. 메모리도 저 함수로 구해지는 (값+1)*sizeof(char) 만큼 바이트를 할당하면 된다.(1은 널터미네이트 문자)
가령 123가나다 <====== 이문자열은 1바이트 3개+2바이트 3개 = 9의 값이 나오므로
10을 인수로 줘서 메모리를 할당하면 된다.

그런데 lstrlenW는 문자하나의 길이는 무조건 2바이트이다. 그러면 위 123가나다 를 실행하면
무슨 값이 나올까....2바이트문자가 6개 있으므로 12가 나온다라고 생각하는데 그게 아니다.
결과는 갯수를 의미하는 6이다. 여기서 길이와 바이트의 차이에 유의해야 된다.
길이는 문자의 갯수이다. 한 음절은 무조건 1개로 처리되므로 메모리 할당시는
위 함수의 (결과값+1)에다가 유니코드문자열사이즈인 sizeof(wchar_t)를 곱해야할 것이다.

그리고 위 문자열들을 컴퓨터 하드디스크에 텍스트파일의 형태로 저장하고자 할때는
멀티바이트형태로 저장해야 텍스트 에디터로 읽는 데 편할 것이다.
그러므로 이 경우는 처음부터 멀티바이트 함수를 써서 문자열 추출및  길이를 구하고, 그 용량만큼 할당해서
CreateFile하는 게 좋을 것이다. 처음부터 유니코드 문자열이라면 WideCharToMultiByte 등의 변환함수를 통해서
멀티바이트로 변환한 후 위의 과정을 거쳐야 할 것이다.