유니코드 인코딩의 종류는 UTF-1, UTF-5, UTF-6, UTF-7, UTF-8, UTF-9, UTF-16, UTF-18, UTF-32, UTF-EBCDIC, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE와 같이 다양하다. 지금은 사장된 것들도 있지만 초급 개발자에게는 여간 헷갈리는 것이 아니다.
애초에 ASCII가 아니고 유니코드를 사용했다면, 특히 4바이트 유니코드를 사용했다면 지금과 같이 수많은 유니코드 인코딩 때문에 헷갈거나 변환을 해야 하는 번거로움은 없었을 것이다. 현재와 고대 문자만 표현한다면 3바이트로도 충분하지만 4바이트가 컴퓨터 연산에 편리하고 먼 미래에 어떻게 될지 모르기 때문에 4바이트가 안전할 것이다. 하지만 뒤늦게 나온 유니코드는 ASCII와 호환성 등 여러 가지 이유로 인해서 수많은 인코딩이 존재한다.
인류가 유일한 표준 문자세트로 4바이트 유니코드를 사용하고 있다면 영어 문서를 저장하기 위해서 지금의 4배 용량의 저장장치가 필요하다. 지금은 별일 아니지만 과거에는 저장 용량은 매우 큰 이슈였다. 필자가 대학생 때 샀던 PC에는 40만원 주고 산 40MB짜리 그 당시로는 대용량 HDD가 달려 있었다. 지금은 2바이트, 4바이트 유니코드가 있지만 여전히 저장 용량 절약 이슈가 존재한다. 언제가 될지 기약할 수 없지만 모든 시스템과 파일이 4바이트 유니코드 단일 체계를 사용하는 날이 올 것이다. 몇십년 후일지 몇백년 후일지는 모르겠다.
(유니코드 인코딩과 타 인코딩 간의 관계)
그럼 유니코드 관련 주요 인코딩의 특징 및 관계, 사연에 대해서 알아보자. 지금은 거의 쓰지 않는 인코딩은 알 필요가 없다.
1. MBCS (Multi Byte Character Set)
유니코드 인코딩이 아니며 ASCII에서 표현하지 못하는 각국의 문자를 표현하기 위해서 사용하는 수많은 문자세트와 인코딩이다. 보통 1,2바이트를 사용하며 ASCII를 포함한다. 나라별로 로케일별로 제각각 이어서 서로 호환이 안 된다. 아직도 수많은 Application이 유니코드 기반이 아니고 MBCS 기반이며 소프트웨어 국제화의 발목을 잡고 있다. Application이 MBCS 기반이어도 Windows는 내부적으로 유니코드(UCS-2)를 쓰기 때문에 Application과 OS를 오가며 문자열들은 계속 변환이 일어나고 이런 과정에서 예상치 못하게 깨지는 문자들이 나오게 된다. 최근의 새로운 개발 환경이나 플랫폼들은 아예 MBCS를 지원하지 않고 유니코드 Application만 제작할 수 있는 경우도 많다. 이런 환경에서만 개발하는 개발자는 MBCS가 뭔지도 모르고 자연스럽게 유니코드 Application을 만들 것이다.
2. UCS-2 (Unicode Character Set-2)
유니코드 문자세트이며 인코딩이다. Windows는 내부에서 UCS-2를 사용한다. C언어에서는 wchar_t(유니코드문자 자료형)로 표현한다. Unix나 Linux에서는 wchar_t는 UCS-4이다. Unix나 Linux에서는 한 글자에 4바이트이니 주의를 하자. 모든 문자가 깔끔하게 2바이트라서 연산이 매우 빠르다. 100바이트에는 딱 50글자가 들어간다. 하지만 ASCII 문자를 표현하기 위해서 NULL문자가 포함되어 있어서 기존의 char * 자료형에는 담을 수가 없다. 또한 문자열 관련된 수많은 함수를 다시 만들어야 했다. 파일에 그대로 기록할 경우 NULL문자로 인해서 기존의 Application이 텍스트 파일이 아닌 바이너리 파일로 인식하는 문제가 있다. 주로 Application 내부 데이터 용도로 사용한다고 보면 된다.
3. UTF-8 (Unicode Transformation Format-8)
유니코드 중에서 가장 널리 쓰이는 인코딩이다. 1~6바이트를 사용한다. BMP만 표현한다면 4바이트까지만 사용하면 된다. 특히 파일저장, 데이터 전송 등에 많이 사용한다. UTF-8의 가장 큰 장점은 위 그림에서도 보이듯이 ASCII, ISO8859-1과 호환된다는 것이다. 즉, UTF-8 문서를 처리하는 소프트웨어는 ASCII와 ISO-8859 문서를 변환 없이 그대로 처리할 수 있다. 반대로 UTF-8 인코딩으로 저장한 문서가 과거 미국이나 독일 Application에서 읽힌다. 물론 지원하지 않는 문자는 깨져서 보일 것이지만 열리기는 할 것이다. 미국과 유럽, 특히 영어권에 매우 유리한 인코딩이다. 이는 UTF-8이 가장 널리 쓰이는 이유이기도 하다.
영어로 된 문서를 저장할 때 용량이 매우 작다. 하지만 한국어(한글)는 한 글자당 3바이트로 용량이 낭비된다. 이또한 UTF-8이 인기있는 이유중 하나다.
그 외에도 UTF-8은 여러 장점이 있다. 데이터를 중간부터 보더라도 몇 바이트만 보면 UTF-8 인코딩인지 알 수 있고 데이터 손실도 거의 없다. UTF-8 데이터 구조는 처음부터 이런 장점을 가지도록 설계가 되어 있는데 이를 설계한 사람의 천재성을 엿볼 수 있다.
또 하나의 장점은 문자열 중간에 NULL(0x00)문자가 나오지 않는다는 것이다. 따라서 파일에 저장해도 바이너리 파일로 인식하는 오류가 없고, C언어와 같이 Null terminated string의 자료형에 담을 수가 있다. 이는 하위호환성에서는 큰 장점이 된다.
단점으로는 가변 바이트를 사용하여 글자 개수를 세려면 한 글자씩 개수를 세야 하는 등의 연산 오버헤드가 있다.
4. UTF-16 (Unicode Transformation Format-16)
유니코드 컨소시엄에서 제안한 인코딩이다. UCS-2와 거의 동일하기 때문에 혼동해서 사용하는 경우가 많다. 하지만 UTF-16은 가변 길이이기 때문에 2바이트 고정 길이를 지칭한 경우라면 UCS-2를 말하는 것을 UTF-16이라고 잘못 부르는 것이다. 최초의 UTF-16은 UCS-2와 동일 했기 때문에 그 잔재가 아직도 남아 있는 것 같다.
Java에서는 문자열의 인코딩에 기본적으로 UTF-16(BE)를 사용한다. Java로 개발을 할 때도 문자 인코딩을 제대로 이해하고 있어야 깨지지 않고 제대로 처리를 할 수 있다.
5. UTF-32 (Unicode Transformation Format-32)
4바이트로 고정된 UCS-4와 동일한 인코딩이다. (현재까지는) 모든 문자들이 UTF-32로 통일된다면 인코딩 변환이 필요 없는 세상이 올 것이다. 하지만 저장 공간 낭비가 심해서 인류가 저장 용량에서 완전히 해방되는 날이 되기 전까지는 유일한 표준이 되기는 어려울 것이다. 또한 UTF-8과는 다르게 데이터를 중간부터 보면 어디가 글자의 시작인지 알 수가 없는 단점이 있다.
이 외에도 수많은 유니코드 인코딩이 생겨났지만 거의 사장되다시피 했다.
Byte Order와 BOM 이슈는 나중에 다루도록 하겠다.
국제화를 이해하기 위한 기초를 다루다 보니 여러 회가 지났는데 다음부터는 본격적인 내용과 기초를 교대로 다뤄볼까 한다.
이 글은 네이버 포스트에 게재할 글입니다.