프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 끼로

안녕하세요. 2일과 17일을 담당하고 있는 박성준입니다.
오늘은 문자열 인코딩에 대해서 이야기를 해보려고 합니다.

게임을 만들다보면 여러가지 형식으로 인코딩된 문자열들을 사용하게 됩니다. 그런데 C++에서는 기본적으로 문자열을 표현하는데 기본적으로 제공되는 것들이 C#이나 다른 최근에 만들어진 언어에 비해 많이 불편합니다..

그래서 저는 C#의 System.Text.Encoding 클래스를 베껴서 C++에서 구현하여 사용합니다..



이것이 문자열 인코딩

모두 아시다시피 컴퓨터는 원래 문자를 표현할 수 없습니다. 숫자만을 표현할 수 있고 저장할 수 있죠. 그래서 컴퓨터에서 문자를 표현하기 위해서는 숫자들로 이루어진 값(바이트)을 특정 문자로 매핑하여 어떤 숫자가 어떤 문자를 표현하는지를 미리 설정해두어야 합니다. 즉, 문자열 인코딩은 지원되는 문자 집합의 각 문자를 해당 문자를 나타내는 숫자 값과 연결하는 것을 말합니다.  char형을 사용하는 문자열 인코딩의 형식은 보통 코드페이지에 의해 구분되며 wchar_t를 사용하는 문자열 인코딩 형식은 기본적으로 Unicode 인코딩 형식입니다. Unicode는 UTF-8, UTF-16(UCS-2), UTF-32(UCS-4) 등이 있는데 윈도우즈에서는 기본적으로 UTF-16을 사용하기 때문에 윈도우즈에서 wchar_t형은 UTF-16이라고 생각하시면 됩니다. 그래서 wchar_t의 사이즈가 2바이트인 것입니다. (리눅스는 UTF-32를 사용한다고 들었습니다. 따라서 리눅스에서 wchar_t의 사이즈는 4바이트 입니다.)
유니코드에 대한 더 자세한 내용은 유인환님께서 쓰신 '2012/01/06 - [프로그래밍] - Unicode 사용하기'를 참고해주세요.


문자열 인코딩은 어디에 쓰지?!

문자열 인코딩은 여러가지 경우에 사용됩니다. 기본적으로 컴퓨터에서 문자를 표현할때는 모두 문자열 인코딩을 사용합니다. 하지만 직접 코드페이지를 입력해주어야 하거나 변환을 해야 하는 경우도 존재하죠. 예를 들면 윈도우즈의 언어설정이 한국어로 되어있는 경우 기본 코드페이지는 한국어 코드페이지(949)로 되어있기 때문에 특별히 신경써주지 않아도 한국어 표현이 됩니다. 하지만 언어 설정이 일본어로 되어 있는 경우 따로 문자열 인코딩을 해주지 않았다면 "안녕하세요" 라는 문자를 출력했을때 "セネウ酩マシシソ・"라는 이상한 일본 문자가 화면에 나타날 것입니다. 또는 유니코드 환경을 사용할 때에도 문자열 인코딩은 신경써야 합니다. 모든 라이브러리가 유니코드를 지원하는것이 아니기 때문에 또는 UTF-16을 사용하고 있지만 UTF-8로 입력이 들어오는 경우도 존재하기 때문에 사용하고자 하는 문자를 명확하게 지정할 수 있어야 제대로 된 문자열을 화면에 출력할 수 있겠죠. 사실 최근에 만들어진 언어들은 문자열 출력에 좀 더 신경써서 만들어졌습니다. C#만 봐도 char, wchar_t 이런것에 전혀 신경쓰지 않고 string이라는 타입에 모든 문자열 형태를 저장할 수 있고 Encoding 클래스를 사용하여 인코딩도 쉽게 설정할 수 있습니다.


C#에서는 어떻게 쓰길래

C#에서는 System.Text에 Encoding이라는 클래스가 존재합니다. 이 Encoding 클래스를 사용하면 문자열 바이트를 한국어로 인코딩을 해서 string을 얻어내거나 한국어 <-> UTF-8, 한국어 <-> UTF-16, UTF-8 <-> UTF-16 등 인코딩 변환도 간단하게 할 수 있도록 만들어져있습니다. 이런 클래스가 존재하기 때문에 문자열을 저장하거나 메시지버퍼에 넣을때에도 원하는 인코딩으로 편하게 변환시킬 수 있습니다.

문자열의 인코딩 형식의 변경도 조금 복잡하긴 하지만 그래도 쉽게 가능합니다. 원래 인코딩이라는게 인코더와 디코더로 이루어져야 하기 때문에 .Net Framework에 있는 Encoding 클래스들 역시 인코더와 디코더의 기능을 가지고 있고 이것으로 문자열 인코딩 형식 변환을 하게 됩니다. 인코더는 바이트 배열을 문자로 표현할 수 있는 특정 범위의 값으로 변경하는것이고 디코더는 인코딩된 형식의 값을 바이트 배열로 변경하는것을 말합니다.


C++에서의 구현

기본적으로 Encoding 클래스의 형태는 C#의 그것과 비슷하게 따라가려고 했습니다. 특별한 이유는 없고 그냥 베낀겁니다. -_-;
특히 C#에서 Encoding.Default, Encoding.ASCII, Encoding.UTF8 이런식으로 자주 사용하는 문자열 인코딩 형식을 쉽게 가져오는 부분과 Encoding.Convert( Encoding.Default, Encoding.UTF8, 바이트배열 ) 이런식의 사용에 중점을 두었습니다.

그래서 다음과 같은 코드를 작성할 수 있도록 하였습니다.
 회사에서 작업한 코드를 올릴 순 없으니 급하게 따로 작성한 코드를 첨부하도록 하겠습니다..
급하게 작업한거라 버그가 있을 수 있으니 그대로 사용하기엔 문제가 발생할 수 있습니다..
그냥 이런식으로도 사용하는구나 정도로 봐주시면 될 것 같습니다...

TextEncoding.zip





받아보시면 Encoding의 구성은 위 그림처럼 되어있을 것입니다. 하지만 외부에서 사용하는건 Encoding 클래스 하나입니다. 사실 ASCII니 DBCS니 SBCS니 해도 내부 구현은 WideCharToMultiByte()와 MultiByteToWideChar()를 사용하여 구현되어있습니다. 그리고 몇몇 부분들은 대충 구현한거라 최적화와는 거리가 먼 코드들이 존재합니다..
먼저 내부 구현부중에 위 코드는 자주 사용하는 인코딩 형식을 쉽게 사용할 수 있도록 만들어준 static 함수입니다. "Encoding::Default()" 이런 코드로 현재 윈도우즈의 코드페이지를 사용하는 인코딩 형식을 사용할 수 있도록 하기 위함입니다. 이 함수들은
내부적으로 이 함수를 사용합니다. GetEncoding() 함수는 코드페이지를 직접 입력하여 인코딩 형식을 사용할 수 있도록 하는 함수입니다. "Encoding::GetEncoding( 949 )" 이렇게 한국어 코드페이지 949를 사용하는 인코딩 형식을 가져올 수 있죠.
그리고 Convert함수를 사용하여 문자열의 인코딩 형식을 변환할 수 있습니다.

이외에도 Encoding 객체를 사용하여 wchar_t를 사용하여 표현되는 문자열을 char를 사용한 해당 인코딩형식으로 변환할 경우에 사용할 수 있는 여러가지 함수들이나 그 반대의 경우에 사용할 수 있는 함수들을 포함하고 있으면 코드페이지를 얻어오거나 인코딩 형식의 이름을 가져오는 함수 등 자주 사용되는 함수들이 포함되어 있습니다. 이 함수들에 대한 자세한 설명은 생략하도록 하겠습니다..


뭔가 급하게 끝나는것 같은 기분이 든다면 그건 착각입니다..


댓글을 달아 주세요

  1. sgpro 2012.01.17 10:43  댓글주소  수정/삭제  댓글쓰기

    고맙습니다~ ^^

  2. 쏠구 2012.01.17 10:44  댓글주소  수정/삭제  댓글쓰기

    얼마전에 UTF-8 Encoding 때문에 고생한 기억이 있어서 그런지 매우 반가운 주제로군요ㅎㅎ
    좋은글 감사합니다 :)

    • Favicon of https://gamedevforever.com 끼로 2012.01.18 15:30 신고  댓글주소  수정/삭제

      문자열 인코딩은 항상 골치아프죠 ㅎㅎ UTF-8이던 UTF-32던 하나만 쓸 수 있으면 참 편할텐데 작업하다보면 어쩔 수 없이 변환을 해야 하는 상황이 생겨서..Orz

  3. Favicon of http://dishdev.me/ Dish 2012.01.18 14:55  댓글주소  수정/삭제  댓글쓰기

    짧지만 이런 글이 검색해서 들어오는 사람도 많을 것 같고
    유용할 것 같아요 ㅋㅋ

    • Favicon of https://gamedevforever.com 끼로 2012.01.18 15:30 신고  댓글주소  수정/삭제

      쓰고 나서 느낀건데.. 지금까지 세개의 글을 올렸는데 모두 게임과 직접적인 연관이 있는 글이 아니네요.. 게임개발포에버인데 저도 게임과 관련된글을 어서 올려야..

  4. Favicon of https://gamedevforever.com 친절한티스 2012.01.18 15:27 신고  댓글주소  수정/삭제  댓글쓰기

    감사합니다. 유용하게 써먹겠습니다 ㅎㅎ

  5. 알콜코더 2012.01.18 17:29  댓글주소  수정/삭제  댓글쓰기

    저는 ATL을 사용합니다. ATL 내부에도 저런 헬퍼 함수들이 있죠.
    자주 쓰는데.. 별 문제는 없는듯.. 예전에 코딩하던 1세대 선배들은 ATL이라면 무조건 싫어하긴 하지만...

    • Favicon of https://gamedevforever.com 끼로 2012.01.19 12:39 신고  댓글주소  수정/삭제

      전 1세대가 아니지만 ATL은 싫어해요.. 지금도 허접이지만 몇년전 더 허접일때 ATL을 막 쓰다가 문제가 생긴적이 있어서.. 사실 제가 허접이어서 생겼던 문제이지만 그 이후로 ATL은 안만지게 되버렸..

  6. 무뇌 2012.02.06 18:37  댓글주소  수정/삭제  댓글쓰기

    아오 ... 감사합니다
    여기올때마다 많이배우고 갑니다 포스팅이 머리에 쏙쏙 들어와요

  7. Favicon of http://blog.wimy.com zelon 2012.02.17 18:48  댓글주소  수정/삭제  댓글쓰기

    와~ 좋네요. 정말 감사합니다. 이제 소스 공개하셨으니 곧 github 에서 볼 수 있는 공개 라이브러리가 되는건가요 ㅎㅎ

  8. dlgPtjd 2014.05.19 13:58  댓글주소  수정/삭제  댓글쓰기

    처음 왔는데 좋네요 덕분에 많이 배우고 갑니다.

  9. Favicon of http://blog.naver.com/yo124night 자칭서태웅 2019.04.18 14:36  댓글주소  수정/삭제  댓글쓰기

    아 이틀째 C# 클라 -> C++ 서버 한글 문자열 송수신 인코딩 문제 때문에 애먹었는데

    Encoding.GetEncoding( 949 )

    마법의 열쇠군요ㅋㅋㅋ

    감사합니다.
    많은 도움이 되었습니다.