결론
멀티 바이트 혹은 유니코드 모두에서 동작하도록 문자열을 다룰 때는 _TCHAR 형과 _T()를 사용한다.
멀티 바이트인지 유니코드인지 환경에 따라 자동으로 변수 이름이나 함수 이름이 변환되겠끔 하기 위해 ‘_t’가 붙은 것을 사용한다.
한가지 팁으로는 유니코드로 한글을 출력하기 위해서는 setlocale() 함수를 사용해야 한다.
Wide Character(wchar_t형)
1byte가 아닌 그 이상의 byte를 차지하는 정수에 저장되는 문자 코드를 의미한다.
흔히 Wide Character로 표현되는 문자 코드는 UNICODE이다.
UNICODE를 Wide Character로 표현하는 방법은 UCS-2(2byte), UCS-4(4byte), UTF-16(2byte), UTF-32(4byte) 등이 있다.
C표준은 Wide Character를 표현하기 위해 wchar_t 데이터 형을 정의하고 있는데, wchar_t의 정확한 크기는 구현에 따라 다르며 MSVC에서는 내부적으로 unsigned short형(UCS-2)이고, gcc는 int형(UCS-4, UTF-8)을 사용한다.
C표준은 wchar_t형의 형식을 통일하는데 실패했으며, 이는 곧 다양한 표현 방법을 선택할 수 있게 되었다는 것을 의미하기도 하는데
즉, wchar_t는 시스템에 따라서 UCS-2 일수도 있고, UTF16일수도 UTF-32일 수도 있다는 것이다.
(gcc에 -fshort-wchar 옵션을 주면 wchar_t가 unsigned short를 사용하도록 설정할 수 있지만, 이렇게 컴파일러 옵션으로 변경했을 경우에 다른 표준 C 라이브러리들이 이 설정에 맞게 동작할지 알 수 없기 때문에 옵션을 설정 안하는 것이 좋다.)
C 표준은 wchar_t형 외에도 wint_t를 같이 정의하고 있는데 fgetc()와 같은 함수들을 위함이다.
wint_t형은 한 개의 유니코드 값을 주고 받기 위해서 함수 인수나 리턴 값으로 사용되며, wint_t의 배열로서 문자열을 나타내지는 않는다.
( 만약 wide character 버전의 fgetc()가 있다면, wchar_t를 리턴하기 보다는 wchar_t 외의 에러 값도 표현할 수 있는 타입을 리턴해야 하는데, 이때 사용하는 것이 wint_t이다.
그냥 int를 써도 무방할 수 있지만 int가 wchar_t와 똑같이 16비트일 경우가 있을 수 있으므로 wint_t를 사용해야 한다. )
MS 윈도우즈에서는 C 표준 말고도 자체 API 상에서 UNICODE를 지원하는데, 이 때는 WCHAR를 사용한다.
(WCHAR는 unsigned short로 MS의 컴파일러에서의 wchar_t형과 일치한다.)
C/C++ 소스 파일은 wide character를 받아들이지 않고, ASCII 파일만을 인식한다.
(ASCII와 호환되는 MBCS나 UTF-8만 가능하다)
대신 C 표준은 wchar_t를 위해 문자열 상수의 변환을 지원하도록 했다.
(즉, 후에 나올 내용 중에 유니코드 환경일 때 문자열 처리 part에서 나올 wide string literal 표현법인 문자열 상수 앞에 L을 붙이는 것이다.)
다만, Wide string literal 방법을 사용했을 때 해석은 MSVC와 GCC가 다르다.
MSVC는 소스 파이 안에 있는 문자열을 시스템의 기본 locale에 따라 인식한 후에 UCS-2로 변환한다.
즉, 컴파일 시점의 사용자 설정을 기준으로 변환한다는 것이다.
(프로그램 출력물 안에는 원하는 대로 UCS-2 문자열로 저장이 된다.)
MSVC의 소스파일에서는
gcc 3.4 이전 버전은 Wide string literal을 제대로 지원하지 못한다.
변환 없이 그저 각 byte를 4byte로 복사해 넣는 방식으로 동작한다.
gcc 3.4 이후 버전은 기본적으로 UTF-8로 인식하고 이를 UTF-32로 변환해서 저장한다.
그리고 입력 문자열을 지정할 수 있는 옵션이 추가되었다.
문자 코드
ASCII 코드
영어, 부호, 숫자 등을 128개의 수로 나타내는 방법, 단점은 영어 이외에 한글이나 다른 언어들은 표현할 수 없다.
멀티 바이트(MBCS = Multi Byte Character Set)
영어는 1byte, 이 외 문자는 2byte로 처리, 하지만 이는 세계 표준이 아닌 MS에서만 사용하는 것이다.
유니코드(WBCS = Wide Byte Character Set)
모든 문자를 2byte로 처리(GCC는 4byte로 처리)
멀티 바이트와 유니코드 환경에 따른 변수와 함수 이름
데이터 타입을 _TCHAR로 쓰면 유니코드 환경일 때 wchar_t 형으로 재정의한다.
Visual Studio에서 유니코드를 사용하기 위해서는 wchar, wprintf와 같은 ‘w’ 문자가 붙은 변수 이름이나 함수 이름으로 사용해야 한다.
하지만 매번 멀티 바이트 환경에서 유니코드 환경으로 변경 후 개발할 때 혹은 그 반대의 경우에 변수 이름과 함수 이름을 바꾸는 작업을 하기에는 너무 번거로움으로 환경이 어떤지 검사하여 알아서 변환해주는 _tprintf() 같은 함수를 사용한다.
TCHAR형 함수들
header file | string.h | mbstring.h | string.h or wchar.h | tchar.h |
header file description | _UNICODE 또는 _MBCS가 정의되어 있지 않다. | _MBCS가 정의되어 있다. | _UNICODE가 정의되어 있다. | _UNICODE 또는 _MBCS가 정의되어 있다. |
문자열 복사 | strcpy | _mbscpy | wcscpy | _tcscpy |
문자열을 사이즈만큼 복사 | strncpy | _mbsncpy | wcsncpy | _tcsncpy |
문자열 길이 확인 | strlen |
_mbslen | wcslen | _tcslen |
두 문자열을 이어주는 | strcat | _mbscat | wcscat | _tcscat |
두 문자열을 사이즈만큼 이어주는 | strncat | _mbsncat | wcsncat | _tcsncat |
문자열 비교 | strcmp | _mbscmp | wcscmp | _tcscmp |
두 문자열을 사이즈만큼 비교 | strncmp | _mbsncmp | wcsncmp | _tcsncmp |
대소문자를 구별하지 않고 문자열을 비교 | stricmp | _mbsicmp | wcsicmp | _tcsicmp |
사이즈만큼 대소문자를 구별하지 않고 문자열을 비교 | strnicmp | _mbsnicmp | wcsnicmp | _tcsnicmp |
문자 찾기 | strchr | _mbschr | wcschr | _tcschr |
문자 찾기(문자열 끝에서부터 검색) | strrchr | _mbsrchr | wcsrchr | _tcsrchr |
문자열 찾기 | strstr | _mbsstr | wcsstr | _tcsstr |
문자 찾기(두번째 인수를 찾고자 하는 문자들의 집합(문자열)으로 구성한다.) | strpbrk | _mbspbrk | wcspbrk | _tcspbrk |
문자열 자르기(두 번째 인수를 집합(문자열)으로 구성 가능하다.) | strtok | _mbstok | wcstok | _tcstok |
문자 치환(첫번째 인수의 모든 문자를 두 번째 인수 문자로 변경한다.) | strset | _mbsset | wcsset | _tcsset |
사이즈 만큼 문자 치환 | strnset | _mbsnset | wcsnset | _tcscnset |
대문자로 치환 | strupr | _mbsupr | wcsupr | _tcsupr |
소문자로 치환 | strlwr | _mbslwr | wcslwr | _tcslwr |
문자열 역정렬 | strrev | _mbsrev | wcsrev | _tcsrev |
멀티 바이트와 유니코드 환경에 따라 문자열 처리 할 때
멀티 바이트로 할 때는 “ “이렇게 더블 쿼터로 문자열을 감싸고,
유니코드로 할 때는 L” “ 이렇게 더클 쿼터로 문자열을 감싸고 앞에 L을 붙여줬다.
멀티바이트 일 때 : MessageBox(NULL, "hello", "hello", MB_OK);
유니코드 일 때 : MessageBox(NULL, L"hello", L"hello", MB_OK);
하지만 만약 유니코드 환경에서 코드를 작성한 후 멀티바이트로 환경을 변경해서(외부 라이브러리와의 호환성 등의 이유로) 코드를 작성할 때는 L”hello”에서 “hello”로 하나하나 바꿔줘야 했다.
그래서 나온 솔루션이 TEXT(””)와 _T(””)을 #define 하는 것이다.
TEXT(””)는 WinNT.h 파일에서 정의 했지만, TEXT 라는 함수 이름도 길어서 tchar.h에서 _T로 이름을 정의 한 것이다.
Win32에서는 TEXT(””)을 쓰고, MFC에서는 _T(””)을 사용한다고 하는데, win32와 MFC에 상관없이 _T(””)을 사용하고 싶을 때는 tchar.h 헤더파일을 포함하면 된다.
MessageBox(NULL, TEXT("hello"), TEXT("hello"), MB_OK);
#include tchar.h
MessageBox(NULL, _T("hello"), _T("hello"), MB_OK);
위와 같이 입력하면 알아서 멀티바이트일 때와 유니코드일 때에 따라 코드를 변환한다.
// 멀티바이트 일 때
MessageBox(NULL, "hello", "hello", MB_OK);
// 유니코드 일 때
MessageBox(NULL, L"hello", L"hello", MB_OK);
결론
멀티 바이트 혹은 유니코드 모두에서 동작하도록 문자열을 다룰 때는 _TCHAR 형과 _T()를 사용한다.
멀티 바이트인지 유니코드인지 환경에 따라 자동으로 변수 이름이나 함수 이름이 변환되겠끔 하기 위해 ‘_t’가 붙은 것을 사용한다.
한가지 팁으로는 유니코드로 한글을 출력하기 위해서는 setlocale() 함수를 사용해야 한다.
"", L"", TEXT(""), _T("") 차이점 : http://x108zero.blogspot.com/2013/12/text-t-l.html
TCHAR, wchar, char란 무엇인가?? : https://redcoder.tistory.com/137
문자열 관련 함수들 : https://mrhook.co.kr/202
와이드 문자란 : https://blog.daum.net/rayolla/376
TCHAR형이란 https://hwan-shell.tistory.com/134
'C > C note' 카테고리의 다른 글
[C Note] Sleep(0)의 의미 (0) | 2022.09.04 |
---|---|
[C Note] Macros Info (0) | 2022.09.04 |
[C Note] 비전공자들을 위한 알아두면 좋은 프로그램과 C언어 기본 개념 (0) | 2022.08.22 |
[C 언어] while문 process(with Assembly) (0) | 2022.06.30 |
[C 언어] if문, strlen() 함수, strcmp() 함수 process(with Assembly) (0) | 2022.06.30 |