본문 바로가기
IT 공부/Windows 개발

[Windows] - 인코딩 환경이 난잡한 이유 (Unicode, MBCS, ...)

by exdus3156 2024. 12. 21.

 

# MBCS(CP949)

 

▷ MBCS는 멀티 바이트 캐릭터 세트의 약자다. MBCS는 유니코드가 아니다!!. 문자를 인코딩할 때 다양한 크기의 바이트로 저장한다는 점에서 UTF-8과 유사해 오해하기 쉽다. 그러나 MBCS는 유니코드 개발 이전에 자 인코딩이 유니코드로 글로벌하게 표준화되기 전에 존재했던 과도기 기술이다.

 

▷ ASCII 코드가 1바이트만을 사용해서 영어 알파벳과 기타 문자를 표시하던 시절, 일본이나 한국과 같은 지역에서는 아스키코드를 포함하여 자신들의 문자열을 표현할 수 있는 인코딩을 개발했다. 아스키코드가 당시 컴퓨터의 실질적 표준이었기 때문에 1바이트로 표현하는 아스키 방식과 호환시키면서 자국의 언어도 표현하려도 보니 "멀티 바이트"로 저장하는 시스템이 되었고, MBCS라는 단어가 붙었다.

 

※ '멀티'이므로 이론상 3바이트도 가능하긴 하지만... 대부분의 문자가 2바이트 이내로 표현된다.

 

▷ MBCS의 문제점은 시스템마다 독자적인 문자열 세트를 인코딩한다는 점이다. MBCS 기술 자체의 유래를 생각하면 당연하다. 초창기 컴퓨터 기술은 서구권을 중심으로 발전했다. 반대로 문자가 복잡하고 종류도 알파벳보다 훨씬 더 많은 동양권은 기술적 변두리에 속했다. 오늘날처럼 글로벌하게 데이터를 통신했던 시절도 아니었다. 그런 상황에서 한국이나 일본, 중국 등 각 나라가 영어를 표현하면서도 자신들만의 문자를 표현하는 인코딩 시스템을 마련했던 것이다. 이게 MBCS다.

 

▷ 국가마다 알파벳의 조합 방식이 다양하니 어쩌면 초창기 컴퓨터 기술 시대에 서로 다른 인코딩 기준을 마련한 것도 이해못할 현상은 아니다. 한글만해도 그 독특한 조합과 과학적인 특성 덕분에(?) 같은 한글이라도 인코딩 방식이 여러 개다.

 

▷ 나라마다 인코딩 표준이 달랐고 MBCS는 철저하게 자국어 표기만을 위해 탄생된 시스템이라는 것이 골자다. 이 시대를 MBCS 춘추전국시대(_헬게이트가 열렸다!_)라고 밈처럼 말하기도 한다.

 

▷ 컴퓨터 기술이 발전하고 정보가 글로벌하게 움직이고 나서야 비로소 문자열을 통합할 생각에 다다랐다. 그도 그럴것이 인터넷의 역사가 1990년대 초에 대중화된 것을 생각하면, 그 전에 문자열을 통합하지 않은 것도 이해가 된다. 여하튼 모든 나라가 컴퓨터로 서로 통신하게 되는 시대가 열리면서 본격적으로 유니코드 같은 표준의 필요성이 대두되었던 것이다.

 

 

 

# 유니코드

 

▷ 유니코드는 쉽게 말해 전 세계의 모든 문자열을 한데 몰아 통합했다는 것이다. 다만 전산적으로 어떻게 저장할 것인지와 관련해 인코딩 종류 자체는 다양한데, 대표적으로 UTF-8, UTF-16 등이 있다. 

 

▷ 종류를 막론하고 유니코드는 아스키코드와 호환성을 가지도록 설계되었다.

 

▷ 유니코드를 지원한다는 말은 내부적으로 데이터를 UTF-8, UTF-16 등 다양한 유니코드 인코딩을 지원해준다는 뜻이다. 물론 오늘날 대체적으로 디폴트는 UTF-8을 기준으로 한다. 그러나 Windows와 관련해선 일이 그렇게 편하게 흘러가진 않았다....

 

유니코드도 자체적으로 역사가 있다. 본래 유니코드란 전 세계의 문자열을 한데 모아 식별 ID를 제공한 테이블일 뿐이고, 실제로 전산적으로 어떻게 저장할지는 인코딩 표준과 관련이 있다. 문제는 이 인코딩 표준 자체가 번잡했다는 점이다. 인코딩 자체가 여러 개라면 문제가 된다.

 

사실상의 표준이 UTF-8이라고는 하지만, Java, C#, Windows API는 모두 UTF-16으로 인코딩한다.

 

※ 참고로 많은 IT 서적에서 이 UTF-16을 가지고 2바이트로 처리하는 문자셋이라고 표현하는데 사실 틀렸다. 애시당초, 2바이트로 고정된 인코딩 방식은 현재의 표준 유니코드에는 더 이상 존재하지 않는다.

 

※  UTF-16은 대부분의 문자를 2바이트 크기로 고정되어 전 세계의 모든 문자열 세트를 인코딩한다. UTF-16 또한 UTF-8처럼 가변 길이 인코딩이다. 오늘날 유니코드에 등록된 문자열은 0xFFFF 크기를 넘는다. 넘는 문자에 대해서 UTF-16은 4바이트로 인코딩한다. 그런데 이 4바이트 문자열은 워낙 희소하게 사용되어 무시하다보니 UTF-16이 2바이트로 고정된 인코딩이라고 오해되곤 한다.

 

그런데 왜 오늘날의 표준인 UTF-8이 아니라 UTF-16을 썼던 것일까? 그것은 바로 너무 빠르게 유니코드를 도입하려고 했기 때문이다. 아이러니하지만 사실이 그렇다. 초기의 유니코드 인코딩 표준에는 USC-2 라는 것이 있었다. 이것은 2바이트의 고정 크기로 문자열을 저장하는 인코딩이다. 마이크로소프트나 자바 진영은 표준을 위해 빠르게 USC-2을 채택했다. 그러나 유니코드 문자 목록이 늘어나면서 2바이트만으로도 부족해지자 다시 새로운 인코딩인 USC-4, UTF-8을 개발했는데, 이미 이 세상의 많은 소프트웨어가 USC-2와 호환되는 상태였다. 그래서 결국 USC-2와 호환되는 UTF-16을 새롭게 개발했고, 이것이 오늘날까지 이어진 것이다. 

 

 

 

# 윈도우즈의 또다른 문제

 

▷ 윈도우즈는 과거 시스템과의 호환성을 중시하기에, 예전에 많은 프로그램들이 문자열을 자국만의 MBCS 방식으로 처리했던 시스템을 그대로 따른다. (이런 태도를 두고 레거시의 MS라고 밈이 있을 정도다.)

 

▷ 예를 들어, 한국의 windows OS의 로컬 인코딩 시스템은 CP949로 이 역시 MBCS의 일종이다. Windows 콘솔 프로그램 환경도 CP949다. 

 

▷ 그래서 Visual Studio는 소스코드 인코딩을 로컬 환경(CP949)에 맞춰주는 방식이 기본으로 설정된다. 바닐라 옵션으로 소스코드를 생성하고 작성하면 CP949로 저장되며, 이것을 UTF-8로 읽으면 한글이 깨져 보인다. 메모장으로 Visual Studio에서 작성한 소스를 열면 ANSI 형식으로 열리는데, 이게 CP949를 뜻한다.

 

▷ 오늘날 문자열 표준이 Unicode이고 인코딩은 UTF-8이므로, 문자열을 다루는 많은 소프트웨어가 대부분 UTF-8을 디폴트로 채택한다. 웹은 말할 것도 없다. 윈도우즈의 메모장과 같은 응용 프로그램도 디폴트는 UTF-8이다. 

 

그런데 윈도우즈 커널과 시스템콜, API 라이브러리들은 UTF-16 기반의 유니코드로 동작한다.

 

그래서 Microsoft에서 문자열을 다루는 환경이 이토록 개판이 난 것이다. 레거시 호환을 위해 MBCS라는 고전적인 인코딩으로 호환되는데 (특히 콘솔 환경), 내부 커널은 유니코드를 도입하겠답시고 너무 이르게 채택한 나머지 UTF-16을 사용했다. Windows 시스템 프로그래밍을 하면 UTF-16 기반의 2바이트를 사용하고 있는데 여기엔 이런 역사가 숨어 있는 것이다.. 정작 오늘날 산업 표준은 UTF-8이니 메모장이나 웹과 같은 응용 프로그램은 되도록 UTF-8을 사용하는 형국이다.