[cpp] printf와 유니코드 출력

@codemaru · October 05, 2016 · 3 min read

wchar_t msg[] = L"안녕하세요.";
printf("%ls 끝.", msg);

이 코드는 유니코드 문자열 "안녕하세요. 끝."을 출력한다. 단순한 이 출력 속에도 복잡한 변환이 숨겨져 있다. printf는 내부적으로 유니코드 문자열을 멀티바이트 문자열로 변환을 시도한다. 이 변환에는 wcstombs와 같은 계열의 함수들이 사용된다. 이 함수는 현재 설정된 로케일을 참조한다. 해당 로케일은 setlocale 등으로 지정할 수 있다. 해당 로케일 정보에 포함된 코드 페이지로 변환한다. 특정 유니코드 문자가 해당 코드페이지로 적절하게 변환이 되지 않을 수도 있다. 그런 일이 발생하면 printf 함수는 실패하고 "안녕하세요" 다음에 있는 "끝"은 출력되지 않는다.

따라서 printf로 유니코드 문자열을 출력할 때에는 로케일이 굉장히 중요하다. 해당 로케일은 앞서도 살펴보았듯이 setlocale로 지정할 수 있다. 일반적으로 UTF-8로 변환해서 출력하기 위해서는 다음과 같이 사용한다.

setlocale("en_US.UTF-8");
wchar_t msg[] = L"안녕하세요.";
printf("%ls 끝.", msg);

하지만 안타깝게도 Visual Studio를 사용한다면 위 코드를 통해서 UTF-8 출력을 사용할 수 없다. setlocale MSDN 페이지를 참고하면 다양한 형태로 로케일을 지정할 수 있는 것을 볼 수 있다. 그리고 en_US.UTF-8은 해당 페이지에서 언급하는 규칙에도 부합하는 것으로 보여진다. 혹시나 하는 마음으로 UTF-8에 해당하는 코드페이지인 65001을 사용해서 en_US.65001을 전달해 보아도 setlocale은 실패한다. 그리고 MSDN 페이지를 좀 더 꼼꼼하게 읽어보면 왜 그런지가 나와 있다.

If you provide a code page value of UTF-7 or UTF-8, setlocale will fail, returning NULL.

— setlocale MSDN

Visual C++을 사용해서는 setlocale을 통해서 UTF-8을 코드페이지로 지정할 방법은 없는 것으로 추정된다. 이뭐병?

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중