작성자: 닉 하지스(Nick Hodges)
요약 : 이 아티클에서는 유니코드와 C++빌더 개발자들이 어떻게 유니코드를 활용할 수 있는지, 그리고 C++빌더 2009에서 유니코드가 어떻게 구현되어 있는지를 살펴봅니다.
서론
인터넷의 등장으로 지역적인 장벽이 없어지고 전세계적으로 소프트웨어를 배포하는 것이 가능해졌습니다. 그 결과로, 애플리케이션은 더 이상 순수한 ANSI 기반의 환경에서만 동작할 수는 없어졌습니다. 유니코드는 전세계적으로 텍스트와 데이터를 전달하는 표준 수단으로 채용되고 있습니다. 유니코드는 사실상 전세계의 모든 표기 체계들을 지원하기 때문에, 유니코드 텍스트는 세계 기술 생태계 전반에 걸쳐 표준이 되었습니다.
유니코드란 무엇인가?
유니코드 는 사실상 모든 문자들을 단일 캐릭터 셋으로 인코딩 할 수 있는 문자 인코딩 방식입니다. 유니코드는 컴퓨터가 전세계 대부분의 표기 체계들을 관리 및 표시할 수 있게 해줍니다. 유니코드는
유니코드 컨소시엄(The Unicode Consortium) 에 의해
관리되며 표준으로 정리 되어 있습니다. 더 간단히 말하자면, 유니코드는 모든 사람들이 상대방의 문자를 사용할 수 있게 해주는 체계라고 할 수 있습니다. 헉! 심지어는
클링곤의 유니코드 버전 도 있습니다(클링곤, Klingon은 스타트렉에 등장하는 외계 종족 이름입니다).
이 연재 아티클은 유니코드가 정확히 무엇이고 어떻게 동작하는가에 대한 완벽한 정보를 제공하기 위한 것은 아닙니다. C++빌더 2009에서 유니코드를 사용하는 데 대한 개략적인 정보를 제공합니다. 유니코드에 대해 자세히 알아보려면, 조엘 스폴스키의 멋진 아티클
“모든 개발자들이 절대적으로 알아야 할 유니코드와 캐릭터 셋에 대한 최소한의 지식” 을 강력하게 권합니다. 조엘은 “유니코드는 그렇게 어렵지 않습니다” 라고 분명히 명시하고 있습니다. 3회에 걸쳐 연재되는 시리즈의 첫 번째인 이 아티클에서는 왜 유니코드가 중요한지, 그리고 C++빌더에서 새로운 UnicodeString 타입을 어떻게 구현되어 있는지 살펴볼 것입니다.
왜 유니코드인가?
C++빌더 2009의 새로운 특징들 중 가장 특기할 만한 것은 유니코드를 개발툴 전반에 걸쳐 완전히 도입했다는 것입니다. 이제 C++빌더의 기본 스트링은 유니코드 기반의 스트링입니다. C++빌더의 IDE와 컴파일러, RTL, VCL 모두는 완벽하게 유니코드 기능이 지원됩니다.
C++빌더에서 유니코드로 이전하는 것은 자연스럽습니다. 윈도우 자체는 유니코드를 완벽하게 인식하므로, 애플리케이션이 유니코드를 지원하고 유니코드 스트링을 기본 스트링으로 사용하는 것은 자연스럽습니다. 또한 유니코드의 채용은 C++빌더 개발자들에게 단순히 윈도우와 동일한 스트링 타입을 사용할 수 있다는 것 외에도 장점이 더 있습니다.
유니코드 지원의 추가는 C++빌더 개발자들은 큰 기회를 가져다 줍니다. C++빌더 개발자들은 이제 유니코드 데이터를 읽고, 쓰고, 받아들이고, 생성하고, 표시하고, 다룰 수 있으며, 이런 기능들은 그대로 개발하는 소프트웨어 제품에도 적용됩니다. 아주 적은 변경으로, 혹은 어떤 경우에는 전혀 변경이 필요 없이, 여러분의 애플리케이션은 여러분, 여러분의 고객, 여러분의 사용자들이 던져줄 수 있는 모든 종류의 데이터에 대한 대비를 할 수 있게 됩니다. 이전까지 ANSI 인코딩 된 데이터에만 국한되었던 애플리케이션들은 간단히 전세계의 거의 모든 캐릭터 셋을 다룰 수 있도록 수정될 수 있습니다.
C++빌더 개발자들은 이제 자신의 애플리케이션들을 글로벌 시장에 내놓을 수 있습니다. 심지어 자신의 애플리케이션에 특별한 현지화 혹은 국제화 작업을 하지 않더라도 말입니다. 윈도우 자체가 수많은 서로 다른 현지화된 버전들을 지원하고 있으며, C++빌더 애플리케이션은 일본어, 중국어, 그리스어, 러시아어 버전 등 윈도우가 지원하는 여러 지역의 컴퓨터들에 맞게 적응하고 실행될 필요가 있습니다. 여러분의 소프트웨어 사용자들이 ANSI가 아닌 텍스트를 입력할 수도 있고 ANSI가 아닌 경로명을 사용할 수도 있습니다. ANSI 기반의 애플리케이션은 이런 상황에서는 의도했던 대로 항상 동작하지 않을 수 있습니다. 완벽하게 유니코드 기반의 C++빌더로 개발된 윈도우 애플리케이션들은 이런 상황에서도 잘 동작할 수 있습니다. 심지어 여러분이 애플리케이션을 다른 언어로 번역하지 않더라도 엔드 유저의 지역이 어디인 지와 무관하게 여러분의 애플리케이션은 제대로 동작할 필요가 있습니다.
기존의 ANSI 기반 C++빌더 애플리케이션에 대해서는, 애플리케이션을 현지화하여 애플리케이션을 유니코드 기반의 시장으로 영역을 넓히는 것은 잠재적으로 거대한 기회입니다. 또한 여러분이 애플리케이션을 현지화하려고 한다면 C++빌더에서는 그 작업을 매우 간단히 할 수 있으며 특히 이제 디자인타임에서의 지원으로 더욱 쉬워졌습니다. 통합 번역 환경(ITE; Integrated Translation Environment)은 여러분이 애플리케이션을 번역하고 컴파일, 배포하는 작업을 바로 IDE 안에서 할 수 있게 해줍니다. 외부의 번역 서비스가 필요한 경우, IDE는 프로젝트를 번역 전문가들이 배포 가능한 익스터널 트랜슬래이션 매니저(External Translation Manager)와 함께 사용할 수 있는 형식으로 엑스포트 해줍니다. 이들 툴들은 델파이/C++빌더 IDE와 연동되므로 애플리케이션의 번역 작업을 원활하고 관리하기 쉬운 프로세스로 만들어줍니다.
세계는 유니코드 기반이며, 이제 C++빌더 개발자들은 네이티브하고 유기적인 방법으로 이 유니코드 세계의 일부가 될 수 있습니다. 따라서 여러분이 유니코드 데이터를 관리하기를 원하거나, 애플리케이션을 글로벌 시장에 내놓고 싶다면, C++빌더 2009로 그렇게 할 수 있습니다.
유니코드 관련 용어들
유니코드에서는 몇 가지 새로운 용어들을 사용하도록 권장합니다. 예를 들면, “문자(character)”라는 용어는 유니코드 세계에서는 여러분이 익숙해왔던 것에 비해서 좀 덜 명확합니다. 유니코드에서 더 명확한 용어는 “코드 포인트(code point)”입니다. C++빌더 2009에서 sizeof(Char)는 2입니다만, 이것은 한 마디로 딱 맞는 말은 아닙니다. 인코딩에 따라 특정 문자가 2바이트 이상을 차지하는 경우도 있을 수 있습니다. 이 2바이트 이상의 연속 바이트들을 “서로게이트 페어(Surrogate Pair)”라고 부릅니다. 코드 포인트는 Unicode.org에서 정의한 엘레먼트가 할당된 유니크한 코드입니다. 대부분의 경우 이것은 “문자”이지만, 항상 그렇지는 않습니다.
유니코드 관련으로 여러분이 보게 될 다른 용어 하나는 “BOM”, Byte Order Mark입니다. 이것은 텍스트 파일에서 사용된 인코딩 타입을 표시하기 위해 텍스트 파일의 시작 부분에 나타나는 매우 짧은 헤더 부분입니다. MSDN에
BOM이 무엇인가에 대한 좋은 아티클 이 있습니다. 새로운 TEncoding 클래스(파트 II에서 살펴볼 것입니다)에는 지정된 인코딩을 리턴하는 GetPreamble()이라는 함수가 있습니다.
필요한 용어들을 설명했으니, 이제 C++빌더 2009에서 어떻게 유니코드 기반의 스트링을 구현했는지 살펴봅시다.
새로운 UnicodeString 타입
C++빌더 2009에서 기본 스트링은 새로 추가된 UnicodeString 타입입니다. 기본적으로 UnicodeString 타입은 UTF-16에 맞춰져 있으며, 이것은 윈도우에서 사용되는 인코딩과 동일한 것입니다. 이전 버전의 C++빌더에서는 기본 스트링의 타입이 AnsiString 이었습니다. C++빌더 RTL은 이전까지 유니코드 데이터를 다루기 위해 WideString 타입을 포함하고 있었는데, 이 타입은 AnsiString과는 달리 레퍼런스 카운팅이 되지 않아 C++빌더 개발자들이 기본 스트링으로서 기대하는 완벽한 기능을 갖추지 못했습니다.
C++빌더 2009에서 새로 추가된 UnicodeString 타입은 AnsiString과 WideString 타입 양쪽 모두의 기능을 갖추도록 설계되었습니다. UnicodeString은 유니코드 크기의 문자나 ANSI의 바이트 단위 크기의 문자를 모두 저장할 수 있습니다. (AnsiString과 WideString 타입은 여전히 사용 가능합니다) Char와 PChar 타입은 각각 WideChar 및 PWideChar 타입으로 매핑됩니다. 스트링 타입들 중 없어진 것은 없다는 것을 말해둡니다. 개발자들이 사용하던 모든 타입들은 여전히 존재하고 이전과 동일하게 동작합니다.
하지만, C++빌더 2009에서 기본 String 타입은 UnicodeString을 의미합니다. 또, 기본 Char 타입은 WideChar이며, 기본 PChar 타입은 PWideChar입니다.
다시 말하면, 다음과 같은 코드가 sysmac.h 헤더에 선언되어 있습니다.
typedef UnicodeString String;
typedef WideChar Char;
typedef PWideChar PChar;
UnicodeString은 다른 모든 스트링 타입들과 대입(assign) 연산에서 호환됩니다. 하지만, AnsiString과 UnicodeString 사이의 대입 연산에서는 적절한 타입 변환이 일어나게 됩니다. 따라서 UnicodeString 타입을 AnsiString 타입에 대입하게 되면 데이터 손실이 일어날 수도 있습니다.
여기서 확실히 해둘 중요한 점 하나는, 이 새로운 UnicodeString이 이전에 스트링을 사용했던 것과 대단히 비슷하게 동작한다는 것입니다. (물론 유니코드 데이터를 저장할 수 있다는 중요한 차이점을 제외하고 말입니다) 모든 스트링 데이터를 더할 수도 있고, 배열 인덱스로 문자를 지정할 수도 있고, + 연산자로 연결할 수도 있고 등등입니다.
예를 들어, UnicodeString 스트링은 이전처럼 배열 인덱스로 문자를 지정할 수 있습니다. 다음 코드를 보시기 바랍니다.
{
String MyString = "This is a string";
Char MyChar = MyString[1];
}
변수 MyChar는 이전처럼 첫번째 인덱스의 문자 ‘T’를 가지게 됩니다. 이 기능에는 전혀 변경이 없습니다. 비슷하게, 유니코드 데이터를 다룰 때도 마찬가지입니다.
{
String MyString = "世界您好";
Char MyChar = MyString[1];
}
변수 MyChar는 첫번째 인덱스의 문자 ‘世’를 가집니다.
RTL에서는 코드페이지들 사이의 변환과 엘레먼트 크기 변환을 명시적으로 할 수 있게 해주는 헬퍼 함수들을 제공합니다. 사용자가 문자 배열에 Move 함수를 사용하는 경우에는 엘레먼트 크기에 대한 추정을 할 수 없습니다.
여러분이 눈치챌 수 있겠습니다만, 이 새로운 스트링 타입에서는 기존 코드를 여러 경우로 나누어 처리할 필요가 생길 수 있습니다. 유니코드의 경우 Char가 1바이트를 표시한다는 것은 더 이상 사실이 아닙니다. 사실, Char가 2바이트라는 것도 항상 사실은 아닙니다! 따라서, 여러분 코드에 얼마간 조정 작업을 해야 할 수도 있습니다. 하지만, 우리는 최대한 변환 작업을 쉽게 할 수 있도록 대단히 많은 노력을 들였으며, 여러분이 상당히 빨리 작업을 완료할 수 있을 거라고 확신하고 있습니다. 이 연재 아티클의 파트 II와 III에서는 새로운 UnicodeString 타입에 대해 더 자세히 살펴보고, 유니코드 지원을 위한 RTL의 몇가지 새로운 기능들에 대해 얘기해본 후, 여러분이 자신의 코드에서 살펴보고 싶어할 만한 특정한 코딩 패턴들에 대해 논의해보겠습니다. 이 연재 아티클들은 여러분의 유니코드로의 변환 작업을 원활하고 수월한 작업이 되도록 도와줄 것입니다.
결론
유니코드를 기본 스트링으로 추가함으로써, C++빌더는 사실상 전세계의 모든 문자들 혹은 코드 페이지들을 입력, 처리, 표시할 수 있게 되었습니다. 여러분이 C++빌더 2009로 개발하는 애플리케이션은 유니코드 텍스트를 쉽게 입력, 표시, 처리할 수 있게 될 것이며, 거의 모든 언어용 윈도우 버전들에서 훨씬 잘 동작하게 될 것입니다. C++빌더 개발자들은 이제 애플리케이션을 쉽게 현지화 및 번역할 수 있게 되어 이전에는 접근하기 어렵던 시장에 진입할 수 있게 되었습니다. 바깥은 유니코드 세상이고, 이제 여러분의 C++빌더 애플리케이션은 그 안에서 함께 살아갈 수 있습니다.
파트 II에서는 여러분이 쉽게 유니코드 스트링을 작업할 수 있게 해주는 C++빌더 런타임 라이브러리(RTL)의 변경 사항들을 살펴볼 것입니다.
원문 :
http://dn.codegear.com/article/38437
(델파이 관점에서 작성된 원문을 C++빌더 관점으로 편역했습니다.)