Mono 내부의 문자열 처리 방식은 UTF-8
지난번에 소개해 드린 모노 프로파일러로,
Visual Studio에서 Mono 용 Profiler 개발
; https://www.sysnet.pe.kr/2/0/1805
JIT 컴파일 시의 메서드 이름을 알아내는 코드를 다음과 같이 작성할 수 있습니다.
void mono_profiler_jit_compile_enter(MonoProfiler *prof, MonoMethod *method)
{
const gchar *methodName = mono_method_get_name(method);
}
보시는 바와 같이 반환 값이 gchar *타입이고, gchar 타입은 GLib 헤더 파일에 char 타입으로 정의되어 있으므로 결국 wchar_t 처리에 대한 고려는 전혀 안되어 있습니다.
그렇다면, 한글 처리가 어떻게 될지 궁금해 지는데요. 이런 예제를 만들고,
using System;
class MainClass
{
public static void Main (string[] args)
{
테스트 ();
}
public static void 테스트()
{
// ...
}
}
프로파일러 코드에서 methodName을 구해 보면, Visual Studio의 Watch 창에는 "methodName 0x005604f8 <Invalid characters in string.> const char *"이라고 표시됩니다. 혹시나 싶어서 wchar_t * 타입으로 강제 형변환해도 깨진 글자로만 출력됩니다. Watch 창에 출력된 주소 "0x005604f8"의 메모리 값을 조사해 보면,
보시는 바와 같이 "ed 85 8c ec 8a a4 ed 8a b8 00"으로 나옵니다. 대충 한글 한 글자당 3바이트가 할당되고 NULL 처리는 단일 '\0' 문자로만 되어 있는 걸로 봐서 UTF16 이상의 인코딩은 아닌 것 같고 UTF-8로 된 듯 한데, 다음과 같이 확인해 볼 수 있습니다.
using System;
using System.Text;
class Program
{
static void Main(string[] args)
{
string txt = "테스트";
Console.WriteLine(BitConverter.ToString(Encoding.UTF8.GetBytes(txt))); // 출력: ED-85-8C-EC-8A-A4-ED-8A-B8
}
}
아하~~~ 맞군요. ^^
그렇다면 혹시 mono 런타임에 ANSI가 아닌 WIDE 타입의 문자열로 반환하는 메서드가 있지 않을까요? 미리 답변을 내리자면, 없습니다.
모노 소스코드의 "\mono\mono\metadata\class-internals.h" 헤더 파일에 보면 MonoMethod는 다음과 같이 정의되어 있습니다.
struct _MonoMethod {
guint16 flags; /* method flags */
guint16 iflags; /* method implementation flags */
guint32 token;
MonoClass *klass;
MonoMethodSignature *signature;
const char *name;
//...[생략]...
}
그리고 "\mono\mono\metadata\loader.c"에 정의된 mono_method_get_name은 그저 MonoMethod 클래스의 name 필드를 반환하는 역할만 합니다.
const char*
mono_method_get_name (MonoMethod *method)
{
return method->name;
}
대신 GLib를 이용하면 다음과 같이 편하게 대응함수를 만들 수 있습니다.
wchar_t* mono_method_get_nameW(MonoMethod *method)
{
const gchar *methodName = mono_method_get_name(method);
wchar_t *pName = (wchar_t *)g_utf8_to_utf16(methodName, strlen(methodName), NULL, NULL, NULL);
return pName; // mono_method_get_nameW에서는 반드시 g_free를 해야 함.
}
참고로, g_utf8_to_utf16 메서드는 내부적으로 g_malloc으로 메모리를 할당해서 UTF-16 인코딩의 문자열을 담은 버퍼를 반환하기 때문에 사용 후 반드시 g_free 메서드로 해제해야 합니다.
그런데... Mono의 전반적인 문자열 처리가 이렇게 1바이트 연산 기반의 utf-8로 되어 있기 때문에 가능한 그대로 따르는 것이 좋습니다. (예를 들어, strlen과 같은 문자열 연산 함수에서 별탈없이 성공하기 때문에.) 단지, 마지막에 출력할 때나 UTF16으로 변환하는 식의 처리만 하는 것이 코드 작성이 간결해 질 수 있습니다.
(그나저나, 요새 잠깐 시간날 때마다 Mono를 살펴보고 있는데... 과히 만족스럽진 않군요. ^^ 아무리 무료로 공개되어 자금 지원의 규모면에서 차이가 있다고는 하지만.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]