프로그래밍/윈도우 프로그래밍

[윈도우] 문자열의 Encoding 방식

jinkwon.kim 2017. 2. 2. 00:43
728x90
반응형

윈도우에서 제공하는 문자열의 Encoding 방식 

출처 : http://eunchul.com/database/board/cat.php?data=Win32_API&board_group=D45ef8ac8c01d4


C++ 문법을 배우고 Win32 프로그래밍을 시작 할 때,
가장 어려운 것중 하나는 엄청난 수의 Win32 DataType들과 생소한 Macro들이었다.

생전 처음 보는 그 녀석들을 이해하려면 상당한 범위를 돌아다녀야 했고,  
이해하기 보다는 대충 이렇게 쓰면 오류없이 컴파일 되더라 정도로 사용하는게 현실이었다.

그 중에서도 문자열부분은 꽤나 두통을 유발하는 것들인데 유니코드고 멀티바이트고 신경안쓰고 대충 만들고 싶어도 어디에서건 꼭 발목을 잡히게 된다.
그렇다고 아주 해결이 안되는것도 아닌데, 그 때 그때 급하게 땜질식으로 코딩을 하다보니
문자열관련 부분에 대해서는 계속 골치가 아플수밖에 없었다.

싱글바이트캐릭터(SBCS : Single-byte character set),
멀티바이트캐릭터(MBCS : Multi-byte character set),
유니코드 ( Unicode characters ), 와이드 캐릭터 ( Wide characters )로 시작한 문자코드들부터 시작해서
wchar_t, char, TCHAR, BSTR, _bstr_t 등의 관련 데이터 타입들.. L, _T()의 매크로들
거기에 기반한 LPSTR, LPCSTR, LPWSTR, LPTSTR, LPCTSTR등의 데이터 타입들에 대해 간략히 보자


지금 정리하는 내용들은 기본적으로 코드프로젝트의 아티클에 대한 정리 요약본이다.
원본 아티클 링크는 다음과 같다.
The Complete Guide to C++ Strings, Part I - Win32 Character Encodings
The Complete Guide to C++ Strings, Part II - String Wrapper Classes

문자 Encoding 방식

싱글바이트캐릭터
SBCS (Single-byte character set)
한 문자 표현에 1Byte를 사용하는 방식이다.
예로 ASCII 코드가 있으며, 한글이나 일본어표현은 불가능하다.



멀티바이트캐릭터
MBCS (Multi-byte character set)
한 문자 표현에 1Byte 이상을 사용하는 방식으로 Windows에서 MBCS에는 딱 두종류가 있다.
SBCS와 DBCS( Double-byte character set) 결국 많아봐야 최대 2Byte라는 얘기다.
한글이나 일본어가 처리되는 기본 방식이다.
즉,

printf( “안녕하삼” );
std::cout<<”배고프네”;
 

  이렇게 코드를 작성하고 컴파일해서 실행했을 때, 이게 바로 MBCS를 사용한 것이 된다.



유니코드
Unicode (wide characters)
유니코드는 모든캐릭터들을 2Byte로 표현하는 표준 Encoding 방식이다.
즉 구조적으로 한 글자가 1Byte, 2Byte, 3Byte 어느것이든 가능한 MBSC와 구분된다.



> C++에서 종료 문자열
SBCS/MBCS
코드상 별도의 구분없이 사용하므로, 기본 C-Style 문자열에서 처럼 ‘\0’ 한번
즉, 0Byte 값이 문자열의 끝을 표현.

Unicode
모든 캐릭터를 2Byte로 Encoding 하므로, 종료 문자열도 ‘\0’이 두번 위치.
즉, 0Byte 2개가 문자열의 끝을 표현.



> Data type
SBCS/MBCS
char : 일반적인 1Byte 문자형 char를 사용해서 표현

Unicode
wchar_t : wide-character 타입 문자형을 사용하며, 값 지정시 prefix L 을 사용한다.
wchar_t wch = L’즐’; //2Bytes
wchar_t* wstr = L”Hi”; // 6Bytes



> 문자열 처리 함수
SBCS
strcpy(), sprintf(), atol()등의 함수

MBCS
_mbscpy()처럼 _mbsXXX()식으로 이름이 붙은 mbcs전용 함수를 사용해야 한다.

Unicode
wcsXXX()식의 함수나 swprintf(), _wtol()처럼 앞에 w등이 붙은 unicode전용 함수를 사용해야 한다.



Win32 API에서 MBCS와 Unicode사용
windows에서는 두종류의 api를 제공한다.
SetWindowTextA() / SetWindowTextW()처럼 ~A()함수는 MBCS용 그리고 ~W()함수는 Unicode용이다.
실제로 코딩 할 때에는 직접 문자열 Encoding에 맞추어 호출하지 않고 Macro를 사용해서 전처리기에 따라 처리를 하게 된다.

즉,


#ifdef UNICODE

   #define SetWindowText SetWindowTextW
#else
   #define SetWindowText SetWindowTextA
#endif



이런식이다.

문제는 이렇게 전처리기를 통해 컴파일시에 적용되기 때문에 발생하는데,
실제로는 코드에 사용된 문자값들을 지정하는 코드들까지 바뀌어야 한다는 것이다.

HWND hwnd = GetSomeWindowHandle();

#ifdef UNICODE

   wchar_t szNewText[] = L"we love Bob!";
#else
   char szNewText[] = "we love Bob!";
#endif

  SetWindowText ( hwnd, szNewText );



이렇게 리터럴값을 지정할 때에도 Unicode경우 L prefix가 붙기 때문에 상당히 귀찮은 작업이 된다.
그리고 결국 이것을 해결하기 위해 몇가지가 더 추가될 수 밖에 없었던 것 같다.

그래서 해결책으로 나온것이 TCHAR 님이시다.

#ifdef UNICODE
   typedef wchar_t TCHAR;
#else
   typedef char TCHAR;
#endif

#ifdef UNICODE
   #define _T(x) L##x
#else
   #define _T(x) x
#endif


이렇게 매크로 되어있기 때문에 TCHAR 타입을 사용하면, 상황에 맞게 wchar_t / char로 구분되어 처리되고,
prefix L의 문제도 _T()를 사용해서 해결이 가능한것이다.
즉, TCHAR과 _T() 매크로를 사용해서 코드를 작성하면, 컴파일러의 옵션변경만으로 MBCS/Unicode 컴파일이 가능해진다.

거기에 더해서 문자열 처리 함수들의 경우들도 strrchr() / _mbsrchr() / wcsrchr()등으로 구분해서 사용하던 것을
_tcsrchr()식으로 _t가 붙은 함수들로 대체 할 수 있다.

이 함수 매크로들은 TCHAR.H에 정의 되어있는데,
http://msdn2.microsoft.com/en-us/library/tsbaswba.aspx 여기에서 확인가능하다.

즉, TCHAR은 Windows에서 MBCS/Unicode 호환코드를 작성하기 위해 사용하는것이다.

또 일반적으로 사용되는 문자열 관련 데이터타입은 다음과 같다.
WCHAR : wchar_t
LPSTR : char*
LPCSTR : const char*
LPWSTR : wchar_t*
LPCWSTR : const wchar_t*
LPTSTR : TCHAR*
LPCTSTR : const TCHAR*

..알고보면 아무것도 아니다; 더 해서.
OLECHAR : Unicode 문자 wchar_t
LPOLESTR : OLECHAR*
LPCOLESTR : const OLECHAR*

Prefix 경우에는
_T(x) : Unicode빌드일 때, L
OLESTR(x) : LPOLESTR 문자열을 지정하기위해 L
TEXT(x), _TEXT(x), __T(x) : _T(x)와 동일

728x90
반응형