인코딩


1 영어 단어 Encoding

코드화, 암호화를 의미한다. 반대말은 디코딩(Decoding).
동영상 관련으로 친숙한 단어이기도 한데, 이 때는 동영상의 형식을 바꾸는 것을 의미한다.

2 컴퓨터에서 문자 정보를 처리하는 일련의 과정

2.1 개요

많은 사람들이 문자 코드와 문자 인코딩을 잘 구분하지 못하지만, 이 둘은 엄연히 다르며, 특히 유니코드에서 다양한 인코딩 방법이 등장하면서 이 둘을 잘 구분해야 할 필요가 생겼다.

문자 코드는 문서를 전자화하기 위해, 각 문자와 추상적인 숫자 사이를 짝지어 놓은 것이다. 이와 반대로, 인코딩은 이 숫자를 실제의 전산기기 안에서 저장, 처리하기 위해 만들어진 숫자의 표현 형식이다. 예컨대 '가', '나', '다' 라는 문자를 각각 추상적인 숫자 1, 2, 3에 짝지어놓은 것이 문자 코드이며, 인코딩은 이 숫자를 01, 02, 03 하는 식으로 쓰는 형식에 해당된다. 예시의 인코딩 상으로는 컴퓨터에서 100개 이상의 문자를 쓸 수 없을 것이므로, 이 제한을 없애려면 인코딩을 바꿔서 001, 002, 003 하는 식으로 써야 할 것이다. 그러나 여기서 인코딩은 바뀌었지만 문자 코드가 바뀐 건 아니다.

초창기의 컴퓨터는 사람과 기계어로만 소통을 했었고, 당연히 사용 과정에 상당한 애로사항을 겪었다. 그래서, 어셈블리어 등의, 사람이 쓰는 문자를 사용할 필요성이 생겼기 때문에, 라틴 문자숫자, 몇몇 특수문자를 128개([math]2^7[/math])의 코드값에 1:1 대응시키는 법을 고안했고, 이것이 바로 최초의 문자 코드라고 할 수 있는 ASCII(American Standard Code for Information Interchange)다.

아스키는 [math]2^7[/math] 곧 7비트로 이루어졌고, 1바이트 단위로 통신할 때 나머지 1비트는 패리티 코드로 쓰게 되어 있었다. 아스키는 이름에서 나오듯이 근본적으로 정보 교환을 위한 규격이었고, 통신 에러를 감지하기 위한 체크섬이 필요했기 때문이었다. 그러나 이런 간단한 체크섬은 얼마든지 회피할 수 있는 에러들이 발생할 수 있었고, 그래서 이런 패리티 코드는 곧 쓰이지 않게 되었다. 컴퓨터가 8비트=1바이트를 사용하게 되자 대부분의 컴퓨터 업체들은 아스키코드의 7비트 맨 앞에 0비트를 써서 8비트를 채운 인코딩을 쓰게 되었다.

ASCII의 이름에서 볼 수 있듯 미국에서 만들어졌는데, 미국에서 쓰이는 영어를 쓰기 적합한 형태로 만들어졌다. 영어에서 쓰이는 라틴 문자는 악상이 없다시피하기 때문에[1] 넣기가 쉬웠던 것.

하지만 이 방식에는 적지 않은 문제가 있었다. 세상에 영어만 하는가? 당장 라틴 문자를 공유하는 유럽 쪽 언어라든가(이런 언어는 악상을 많이 쓴다), 동아시아(한자,한글,가나)와 아랍, 아프리카 등, 영어를 제외한 다 적기엔 여백이 없을 정도의 많은 수의 언어는 하나도 고려하지 않았던 것이었다.[2] 그래서 8비트 아스키 인코딩에서 비어있는 127 이후의 빈 공간을 다양한 문자로 채워넣는 인코딩들이 등장했는데, 표준이 아니었으므로 회사마다 모두 다른 문자를 할당했고, 또 각국이 자국어 표기를 위해 이 공간을 활용하면서 표준화의 헬게이트가 열렸다.

2.2 춘추전국시대

컴퓨터상에서 글을 쓸 수 있게 할 수 있는 필수요소임과 동시에, 유니코드 발족 전까지 국가별 문자 처리 정보를 혼돈의 카오스로 만든 만악의 근원

미국을 제외한 나라에서 여덟번째 비트 자리를 활용하게 되면서 이른바 헬게이트가 열려버렸다. 국경을 벗어나면 코드가 와장창 깨져버린다는 것이다(...). 예컨대 미국에서 제작된 대부분의 SW에서 확장아스키 127 이후의 영역은 프로그램 테두리 등을 그리기 위한 선문자에 할당되었는데[3], 완성형 한글이 로드된 DOS에서 그 프로그램을 로드하면 이 테두리가 모두 깨진 한글로 표현되었다.

a010101.gif

이렇게. 쳐컴컴컴컴컴컴컴컴캑

영어 이외의 언어를 위해서는 국가별로 인코딩 표준을 만들어야 했고, 그 중 대표적인 것이 한국의 완성형조합형. 하지만 이것도 한계가 있었고[4], 한 문서에 여러 언어를 써야 하는 상황[5]에서는 그야말로 답이 없다.

그래서, 이 문제를 해결하기 위해 모든 문자 체계를 한데 몰아넣은 인코딩, 유니코드가 탄생하게 되었다.

2.3 유니코드 발족 이후의 역사

2.3.1 UCS-2

1980년대부터 7비트 아스키코드의 한계를 벗어나면서 좀더 많은 문자를 표현할 수 있는 멀티바이트 인코딩에 대한 요구가 늘어나며 유니코드 위원회가 발족되었다. 최초의 유니코드 초안에 포함된 문자들은 2^16개(65536개)를 넘지 않았으므로 이진수 16자릿수=2바이트를 써서 인코딩을 하면 모든 문자를 쓸 수 있었다. 이렇게 해서 최초의 유니코드 인코딩이자 고정 2바이트 인코딩인 UCS-2가 탄생했다.

그러나 유니코드에 점점 더 많은 문자와 기호들이 추가되자 65536개를 넘어서서 2바이트 안에 다 담을 수 없는 사태가 발생했다.[6] 그래서 IEEE에서 고정 4바이트(32비트)를 사용하는 UCS-4 인코딩을 제안하였다. 그러나 유니코드 콘소시엄을 구성하는 대부분의 회사들은 이미 2바이트 기반 기술에 너무 많은 투자를 해놓은 상태였던 데다가, 대부분의 라틴문자가 8비트 안에 들어가고,세상에서 주로 사용되는 문자 거의 대부분[7]이 2바이트 이내에 들어가는 상황에서 한 글자당 4바이트 인코딩은 지나친 용량의 낭비라는 점이 문제가 되어 거의 채택되지 않았다.

2.3.2 UTF-16

이러한 상황을 해결하기 위해 가변 길이 인코딩 기법인 UTF-16이 등장하였는데, 이는 기본적으로는 UCS-2와 같지만, 2바이트를 넘어서는 문자에 대해서는 4바이트로 표현하는 것이다. 이를 위해 0xFFFF[8]를 넘는 값을 가지는 유니코드는 코드값에서 0x10000을 뺀 뒤 20비트로 표현하여 이것을 10비트씩 쪼개어, 각 10비트값에 각각 0xD800[9]과 0xDC00[10]을 더해서 2개의 16비트(총32비트)로 인코딩하는 것이다.

이렇게 하여 일반적인 상황(대부분의 한글, 한자, 일본어 등을 포함한 기본 다국어 평면)에서는 기존의 UCS-2 16비트 인코딩과 호환을 유지하면서도 16비트를 넘어서는 문자를 가변 길이 인코딩으로 표현가능하게 되었다.

다만 UCS-2와 UTF-16는 (코드값이 동일함에도 불구하고) 기본 아스키 코드로 작성된 문서와는 호환되지 않았고, 설상가상으로 컴퓨터 시스템에 따라 1Word 내에서 byte의 순서를 처리하는 방식이 모두 달랐기 때문에(엔디안 문제) 호환성에 문제가 있었다. [11] 엔디안 문제 때문에 BOM(Byte Order Mark)를 달아서 빅/리틀 엔디안을 구분하게 되어 있지만 시스템에 따라 달지 않는 경우도 있는 등 [12](그리고 리틀 엔디안을 사용하는 시스템에서는 BOM이 안 붙은 파일을 디폴트로 리틀 엔디안으로 읽고, 글자가 깨지는 경우가 허다하다) ......혼파망. 오죽하면 인터넷에서의 정보교환에는 '유니코드'(원래 ucs-2라고 써야 맞겠지만 이런 식으로 부정확하게 언급된다.[13]) 내지는 UTF-16을 아예 쓰지 말라는 권고하는 글을 심심찮게 볼 수 있다.

2.3.3 UTF-8

UTF-8은 총 최소 1바이트, 최대 6바이트를 사용하는 가변 인코딩이다.

7비트 이내의 코드값에는 맨 앞 비트를 0으로 붙이고, 11비트 이내의 코드값은 총 2바이트로 표현하는데, 첫 바이트의 첫 3비트를 110, 둘째 바이트의 첫 2비트를 10으로 하고 각 바이트의 나머지 공간[* 8-3+8-2=11)에 코드값을 써넣는다. 16비트 이내의 코드값에는 총 3바이트를 써서 첫 바이트의 첫 4비트를 1110, 둘째~셋째 바이트 첫 2비트를 10으로 하고 각 바이트의 나머지 공간[14]에 코드값을 써넣게 되어 있다. 이런 식으로 이어진다.

코드값의 자릿수첫 바이트둘째 바이트셋째 바이트넷째 바이트다섯째 바이트여섯째 바이트
7비트0xxxxxxx
11비트110xxxxx10xxxxxx
16비트1110xxxx10xxxxxx10xxxxxx
21비트11110xxx10xxxxxx10xxxxxx10xxxxxx
26비트111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
31비트1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx

예시 : 문자 A의 아스키코드값은 65로,이는 16진수 0x41(0100 0001)인데, 7비트 이내로 표현가능하므로 UTF-8로도 0x41로 표현된다.
한글 '갑'의 유니코드값은 16진수 0xAC11(1010 1100 0001 0001)인데, 이는 총 16비트가 필요하므로 1110 1010 1011 0000 1001 0001 으로 표현한다. 한글을 표현하는데 2바이트가 아니라 3바이트가 들어간다는 점에 유의.

유니코드의 맨 처음부분에 있는 기본 기호 및 라틴 문자들은 기존의 아스키코드와 코드값이 같은데, UTF-8 인코딩을 쓰면 예시에서 보는 것처럼 이 부분이 아스키코드[15]와 똑같게 인코딩된다. 즉 아스키 문서는 그대로 UTF-8 문서로 읽을 수 있다.

유니코드가 널리 쓰이기 전부터 형성된 인터넷 문서들은 대부분 아스키코드를 기본으로 해서 작성되었고, 특히 기존의 html태그나 자바스크립트 등 아스키로 구축된 사이트를 별다른 변환처리 없이 그대로 쓸 수 있는 엄청난 장점이 있었다. 더군다나 UTF-8은 엔디안에 상관없이 똑같이 읽을 수 있었으므로 크로스플랫폼 호환성도 뛰어났다.

이런 장점으로 인해 인터넷 사이트에서 가장 많이 쓰이는 인코딩으로 되었다. 과거 한국에서는 국가별 인코딩인 EUC-KR을 쓰던 사이트들이 많이 남아있어서, 한때는 각종 브라우저에서 '주소를 UTF-8로 보냄' 옵션을 체크 해제하는 팁(주로 한글 이름으로 된 파일의 링크를 클릭해서 404에러가 뜰 때)이 널리 퍼졌으나, 지금은 일부 구닥다리 사이트를 제외하면 UTF-8로 옮겨가는 추세이며 관공서 사이트도 차츰 UTF-8 기반으로 바뀌고 있다.

2.4 관련 항목

  1. résumé 등의 악상이 있는 영어 단어가 있기는 하지만, 죄다 프랑스어 직수입 어휘이며 그나마도 이런 단어는 몇 없기 때문에 사실상 악상을 쓰지 않는 언어라고 봐도 무방하다. 악상을 쓰지 않는 또 다른 언어는, 바로 라틴 문자라는 이름의 유래가 된 라틴어.
  2. 아스키는 애초에 미국에서 미국용으로 만든 코드니 이런 비판은 억울한 면이 있다.
  3. 당시는 GUI환경을 위한 기반이 제대로 갖춰지지 않아서 문자 기반 환경에 선문자를 출력해서 테두리나 표 등을 그렸다.
  4. 특히 한글 인코딩조합형 완성형 논쟁이 있었다.
  5. 대표적으로 외국어 학습용 교재
  6. 유니코드 항목에서도 알 수 있지만 현재까지 할당된 문자들은 최대 4바이트까지 쓰이고 있다.
  7. 기본 다국어 평면, BMP
  8. 이진수 1111 1111 1111 1111, 즉 16비트로 표현할 수 있는 최대 숫자.
  9. 1101 10 00 0000 0000
  10. 1101 11 00 0000 0000, 참고로 가변길이 인코딩에 사용되는 이 두 유니코드값은 유니코드표에서는 이 용도로 쓰기 위해 비워두었다.
  11. 예컨대 '갑'이라는 한글은 16비트로 표현하면 0xAC11인데, 빅 엔디안에서는 앞 바이트인 AC를 메모리의 첫 주소에, 뒤 바이트인 11을 다음 주소에 할당하지만, 리틀 엔디안에서는 순서가 반대이다. 리틀 엔디안이 언뜻 보기에는 비직관적으로 보이지만 8비트와의 하위호환성은 좋다. 리틀 엔디안을 사용하는 대표적인 사례로는 인텔 x86이 있는데, 그 인텔 시스템에 올라앉아 있는 자바 가상머신에서는 빅 엔디안을 사용한다...
  12. MS윈도우즈 XP 등의 메모장에서 텍스트를 unicode(빅 엔디안)형식으로 저장하면 BOM을 꼭꼭 붙이지만, 빅 엔디안을 사용하는 많은 시스템은 BOM을 아예 달지 않는다.
  13. 윈도우 기본 메모장에서 저장할 때 인코딩 선택 메뉴에서 ucs-2를 '유니코드'라고 써놨기 때문.
  14. 8-4+8-2+8-2=16
  15. 정확히 말하면 7비트 아스키코드 앞에 0비트 하나를 붙인 것