[C++]

CHAR/ TCHAR/ WCHAR

럭키🍀 2022. 4. 21. 11:48

문자열을 표현하기 위해 사용하는 CHAR타입의 배열!

그런데 C++을 하다보면 CHAR,TCHAR,WCHAR을 혼용해서 쓸 때가 많다.

 

그래서 그 차이점을 비교해보려한다.

 

우선 아스키코드, 멀티바이트, 유니코드에 대해 먼저 보자면.

1.아스키코드(ASCII)

아스키코드는 ANSI에서 만든 미국정보교환표준부호 이다. 7비트 부호체계이며 영문 키보드로 입력할 수 있는 모든 기호들을 128개로 나타내긴 했지만 아스키코드의 모든 문자크기는 1byte로  2byte 이상의 코드를 표현할 수 없었다. 

 

2.멀티바이트 문자 집합.

멀티바이트 문자 집합은 아스키코드(1byte)에 다른문자(2byte)등을 포함한 문자 집합이다.

그래서 한 문자가 영어일땐 1byte이며 상황에 따라 2byte이상이기도하다. 즉, 특정 문자 집합마다 코드 페이지가 존재해 그 코드번호를 한글코드페이지로 해석하면 한글이 나오지만 일어로 해석하면 일어가 나오는 문자집합이다.

보통 이상하게 깨지는 문자들은 멀티바이트 문자집합인데 MS에서 만든 표준으로 세계표준은 아니기 때문일어난다.

 

3.유니코드

유니코드는 세계표준으로 2byte크기를 가지고 있고 아스키코드 문자를 포함한 거의 모든 문자를 표현한다. 각각의 특정 문자는 고유의 유니코드 값을 가진다.

 

이렇게 사용하는 문자의 표현 방법이 여러가지이다. 그럼 이를 어떻게 반영해서 문자열을 처리하는지 자료형을 보자.

 

  char WCAHR TCHAR
문자 크기 1byte 2byte 설정에 따라 컴파일시 char이나 wchar로 확장된다.
타입 ASCII UNICODE 프로젝트 설정에 따라 char이면 ASCII, wchar이면 UNICODE
기타   whar_t char
인코딩 방법   UTF-8, UTF-16  

wchar_t는 WCHAR로 window kit에서 치환돼서 쓰이는 16-bit (2byte) 유니코드 캐릭터이다. w는 Wide로 유니코드는 한 문자당 char의 두 배의 크기를 필요로한다. 대표로 인코딩 되는 방법이 UTF-8과 UTF-16이다.

UTF-8과 UTF-16의 차이는 문자를 표현 할 때 최소 1byte(8bit)가 필요하나, 2byte(16bit)가 필요하나에 차이가 있고 이는 정해주지 않는 이상 compiler-specific이다. WCHAR은 C표준에서 만든 것으로(MS와 상관x), 이를 MS에서는 UTF-16 으로 인코딩해 unsigned short으로 구현하고 있을 뿐이다. 그리고 VS는 #define UNICODE가 지원되고 있다. 이걸로도 필요하면 프로젝트 설정을 할 수 있다.

https://docs.microsoft.com/ko-kr/cpp/cpp/data-type-ranges?view=msvc-170 

 

데이터 형식 범위

자세한 정보: 데이터 형식 범위

docs.microsoft.com

그럼 언제 어떤 타입을 사용하느냐..?

프로그램 개발 환경이 '멀티 바이트 문자 셋'이라면 char

프로그램 개발 환경이 '유니코드 문자 셋'이라면 WCHAR

프로그램 개발 환경이 '문자셋과 상관없이'개발하고싶다면 TCHAR을 사용한다.

나같은 경우는 거의 TCHAR을 사용하고 필요에 따라 언리얼에서 한글을 사용해야하면 cpp파일을 저장할 때 새로운 이름으로 저장>옵션으로 인코딩을 해 사용한다. 

위와 같이 문자집합을 멀티바이트로 설정하면 

이렇게 전처러기를 멀티바이트(_MBCS)로 설정한다. 유니코드시 상속된값에 _UNICODE, UNICDE가 둘 다 설정된다.

THCAR 타입의 문자열에 마우스 오버를 하면 멀티바이트시 typedef char TCHAR, 유니코드시 typedef WCHAR TCHAR로 뜬다.

 

 

참고로

memset이나 ZeroMemory같은 것으로 변수나 구조체, 배열 초기화 할 때 크기를 상수값으로 넣는 것보다 sizeof(변수 타입)를 하는게 더 좋다.

예를들어

const DESC_SIZE=100;

TCHAR description[DESC_SIZE];

이렇게 선언된 문자열이 있었는데

ZeroMemory(description,DESC_SIZE);

이렇게 쓰였는데 문자열을 유니코드 타입으로 바꾸게 된다면 WCHAR description[DESC_SIZE];이 되는 것이고 실제 배열 크기는 DESC_SIZE*2바이트가 된다. 

그러면 ZeroMemory(description,DESC_SIZE);는 반만 초기화하게된다.

그래서 만약 상수를 꼭 써야한다면 ZeroMemory(description, DESC_SIZE*sizeof(WCHAR)); 하는게 낫고 차라리

ZeroMemory(description, sizeof(description))하는게 더 낫다.

 

물론 만약 description이 포인터라서 상수 크기로 동적할당 받아서 쓰는 거라면 

TCHAR* pDescription = new TCHAR[DESC_SIZE];

ZeroMemory(description, DESC_SIZE*sizeof(TCHAR));

하면 문제가 없다.

t로 시작하는 문자열 함수는 대부분 위와 같다.

 

 

'[C++]' 카테고리의 다른 글

[C++ 20] Module  (1) 2024.11.13
Modern C++ #2 스마트 포인터(smart pointer)  (0) 2021.09.19
STL #1 Vector  (0) 2021.08.24
포인터 1 - 포인터, 참조 기초  (0) 2021.08.24