Programming Language/C/C++

[C/C++] 한글 출력 오류, 유니코드, MBCS, 국제화

깐요 2017. 6. 1. 11:51

한글 출력 오류

VS 2017을 이용하면서 학습하던 중에 갑자기 한글 출력이 이상하다...

컴파일러가 음절 사이사이에 공백이 생긴 상태로 출력한다

#include <iostream>
#include <string>
 
using namespace std;
 
int main()
{
    char ch1[20] = "안녕하세요.";
    char ch2[20];
    string str1 = "양배추한닢입니다.";
    string str2;
 
    cout << ch1 << endl;    //안녕하세요.
    cin >> ch2;
    cout << ch2 << endl;    //ch2 입력 내용
    cout < str1 < endl;    //양배추한닢입니다.
    cin >> str2;
    cout << str2 << endl;    //str2 입력 내용
 
    return 0;
}



띄어쓰기가 구별되기는 하지만 무시하고 보기에는 너무 불편하다

아무래도 글을 쓰는 시점으로 어제 Windows10 레드스톤2로 업데이트하면서 무언가가 바뀐 것이 문제인듯하다


ASCII? SBCS? MBCS?

ASCII 문자 집합은 0x00 ~ 0x7F 범위에서 문자를 정의한다

주로 유럽의 문자 집합의 수에서는 0x80 ~ 0xFF 범위의 확장 문자를 정의하기도 한다

따라서 ASCII 집합은 물론 많은 유럽 언어의 문자 집합을 표현하는 데에 8비트의 SBCS(싱글바이트 문자 집합)만으로도 충분하다

그러나 한국어와 같은 비 유럽 문자 집합의 경우는 표현의 한계가 있기때문에 MBCS(멀티바이트 문자 집합) 인코딩이 필요하다

MBCS는 1바이트와 2바이트 문자로 구성될 수 있다

따라서 멀티 바이트 문자열은 싱글바이트 및 더블 바이트 문자를 함께 포함할 수 있다

MSDN "싱글바이트 및 멀티바이트 문자 집합"::https://msdn.microsoft.com/ko-kr/library/4bb3e64h.aspx


멀티 바이트 문자의 각 바이트는 8비트 char로 표현될 수 있다

그러나 값이 0x7F보다 큰 char 형식의 문자는 음수의 값을 가지게 되면서 예기치 않은 결과를 만들 수 있다

따라서 unsigned char로 표현하는 것이 가장 좋다

MSDN "SBCS 및 MBCS 데이터 형식"::https://msdn.microsoft.com/ko-kr/library/12eta419.aspx


유니코드? 와이드 문자 집합

와이드 문자는 2바이트 다국어 문자 코드다

유니코드는 전 세계 컴퓨터 환경에서 사용되는 모든 문자를 표현할 수 있도록 한다

유니코드는 컴퓨터 소프트웨어의 국제화와 지역화에 널리 사용한다

위키백과 "유니코드"::https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C


와이드 문자는 wchar_t형식이고 문자열은 wchar_t[] 배열이나 wchar_t* 포인터로 표현한다

와이드 문자는 16비트 문자 인코딩의 형식이다

문자 앞에 접두사 L을 사용하여 와이드 문자로 나타낼 수 있다 문자열도 마찬가지다

예를 들면 L"Hello" 와 같다


일반적으로 와이드 문자는 멀티바이트 문자보다 메모리 공간을 더 많이 차지하지만 처리 속도는 더 빠르다

그리고 멀티 바이트 인코딩에서는 한번에 한 개의 로캘만을 표현할 수 있지만 유니코드 표현에서는 전 세계의 모든 문자 집합을 동시에 표현할 수 있다

MSDN "유니코드: 와이드 문자 집합"::https://msdn.microsoft.com/ko-kr/library/dtxesf6k.aspx

MSDN "문자열 및 문자 리터럴(C++)"::https://msdn.microsoft.com/ko-kr/library/69ze775t.aspx


wchar_t, wstring, wcout, wcin

표준 문자열 라이브러리 함수들도 유니코드 함수로 사용해야 한다

strlen() -> wcslen()

strcat() -> wcscat()

strchr() -> wcscmp()

strcpy() -> wcscpy()

strstr() -> wcsstr()

strrev() -> _wcsrev()


유니코드 문자를 다루는 방법을 알았으니 코드를 수정해보자

하지만 이번엔 출력조차 하지 못한다

왜냐하면 아직 한가지 작업이 더 남아있기 때문이다


locale 클래스, imbue

한글을 출력하기 전에 로케일 설정을 한국으로 바꿔줄 필요가 있다

그러기 위해서는 locale 클래스를 불러와서 로캘을 바꿔주는 imbue를 사용하여 전역 로캘의 상태를 조정한다

다음과 같이 코드를 상단에 추가하면 된다

...

std::wcout.imbue(std::locale("kor"));

...

전체 로케일 설정을 하고자 한다면

std::locale::global(locale("kor"));

명령문을 상단에 추가하면 된다

kor이 아닌 빈칸으로 두면 현재 시스템의 로캘로 자동으로 설정된다

MSDN "locale 클래스"::https://msdn.microsoft.com/ko-kr/library/1w3527e2.aspx

#include <iostream>
#include <string>
#include <locale>

using namespace std;

int main()
{
	wcout.imbue(locale("kor"));    //한국으로 지역 설정
	wcin.imbue(locale("kor"));

	//와이드 문자열 리터럴
	wchar_t ch1[20] = L"안녕하세요.";    //접두어 L을 붙여준다
	wchar_t ch2[20];
	wstring str1 = L"私の名前は양배추한닢です!.";
	wstring str2;

	wcout << ch1 << endl;    //안녕하세요.
	wcin.getline(ch2, 20);
	wcout << ch2 << endl;    //ch2 입력 내용
	wcout << str1 << endl;    //양배추한닢입니다.
	getline(wcin, str2);
	wcout << str2 << endl;    //str2 입력 내용

	return 0;
}




궁금해서 일본어와 한자를 사용해봤는데 잘 출력된다


잘못된 부분을 발견했을 때 지적해주시면 감사드리겠습니다

320x100