오늘은 BOM(Byte Order Mark)에 대해서 알아보려고 한다. BOM은 바이트 순서를 나타내는 표식이고 바이트 순서뿐만 아니라 이 파일이 어떤 인코딩을 사용했는지도 나타낸다. BOM이 생겨난 사연에 대해서 알아보자.
개발자라면 모두 알고 있겠지만 CPU마다 바이트 순서가 다르다. 바이트 순서를 선택할 수 있는 CPU도 있다. 0x1234는 0x12, 0x34라고 표시하는 것이 자연스럽다. 이런 순서를 빅 엔디언(Big-endian)이라고 부르며 초창기 대부분의 CPU는 이런 아키텍처를 사용했다. 하지만 인텔에서 x86 CPU를 만들면서 적용한 아키텍처는 이와는 정반대다. 0x1234를 0x34, 0x12라고 표시를 했다. 이를 리틀 엔디언(little-endian)이라고 한다.
인텔이 x86 CPU에 이런 아키텍처를 적용한 이유는 덧셈을 조금 더 단순하게 해서 덧셈 회로를 조금이라도 작게 만들기 위한 것이라고 전해지고 있다. 숫자를 반대로 하면 앞쪽 바이트부터 더해서 순서대로 자리 올림을 하면 된다. 우리가 현실에서 덧셈을 할 때 1의 자리부터 거꾸로 더해나가는 것이 더 간단하다는 것을 생각해보면 숫자를 반대로 표시하는 것이 왜 덧셈을 할 때 간단하지 알 수 있다. 지금은 CPU가 한 바이트씩 더하지를 않기 때문에 별 차이도 없어져버렸다.
이렇게 인텔은 주로 리틀 엔디언 아키텍처를 사용하고 대부분은 빅 엔디언을 사용하지만 우리가 사용하는 PC는 거의 인텔 계열 CPU를 사용하기 때문이 어떻게 보면 리틀 엔디언 환경에 접할 가능성이 더 높다.
이렇게 세상에는 두 가지 바이트 순서가 존재하게 되어서 파일을 저장한 후에 다른 컴퓨터에서 읽으면 제대로 읽혀지지 않는 일이 빈번하게 발생하게 되었다. 또한 네트워크를 통해서 데이터를 전송할 때도 문제가 발생했다. 그래서 바이트 순서 규칙을 하나로 정해놓고 자료를 전달한 후에 현재 시스템과 반대로 된 바이트 순서 데이터를 읽을 때는 바이트 순서를 다시 반대로 바꿔줘야 했다.
개발자들이 흔히 하는 실수는 바이트 순서를 현재의 시스템에서 바이트 순서를 보고 짐작하여 메모리를 직접 접근하도록 개발을 해서 다른 시스템에서 동작하지 않게 되는 것이다. 또 시스템간에 파일을 교환할 때바이트 순서를 고려하지 않는 것이다. 소프트웨어를 설계할 때 신경을 써야 할 부분이다.
이런 현상은 인코딩과 관련해서도 똑같이 일어난다. 현재 데이터의 문자가 어떤 인코딩을 사용하고 있는지도 헷갈리는 것이다. 앞부분 몇 바이트를 보니 ASCII 같은데 실제로는 UTF-8 일수도 있고 EUC-KR 문서일 수도 있다.
그래서 문서나 데이터는 자신이 사용한 인코딩과 바이트 순서를 스스로 알려주는 것이 좋다. 이를 Self-Identification이라고 한다. 이런 용도로 사용하기 위해 표준을 정한 것을 BOM이라고 한다. BOM은 파일의 맨 앞에 붙으며 기존의 정상적인 문자에서는 나올 수 없는 문자로 구성이 되어 있다. 그럼 BOM은 어떤 것이 있는지 보자.
EF BB BF : UTF-8
FE FF : UTF-16 빅 엔디언
FF FE : UTF-16 리틀 엔디언
00 00 FE FF : UTF-32 빅 엔디언
FF FE 00 00 : UTF-32 리틀 엔디언
UTF-16과 UTF-32는 엔디언에 따라서 글자 내의 바이트 순서가 반대이다. UTF-8은 바이트 순서가 고정이므로 BOM이 한가지 밖에 없다. 여기서 가장 문제가 되는 것은 UTF-8의 BOM이다. 가장 널이 쓰이는 유니코드 파일의 인코딩이 UTF-8인데 UTF-8의 BOM은 개발자를 여간 괴롭히는 것이 아니다.
UTF-8의 BOM은 BOM 자체가 문제라기 보다는 시스템 또는 어플리케이션에 따라서 BOM를 사용하기도 하고 사용하지 않기도 한다. 또는 두 경우를 모두 지원하기도 한다. 그 조합이 워낙 많아서 헷갈리곤 한다. UTF-8 문서에는 BOM이 없어도 대부분의 경우 UTF-8 문서인지 알 수가 있다. 그래서인지 Unix나 Linux 시스템에서는 BOM이 없는 UTF-8을 이용한다. 반대로 마이크로소프트는 철저히 BOM을 사용한다.
Unix나 Linux에서 또는 오픈소스 개발툴에서는 소스코드에 BOM이 있어서 제대로 읽지 못하기도 하고 HTML 파일에 BOM이 있을 경우 웹서버에 따라서 BOM이 웹브라우져 화면에 출력되기도 한다. 특히, 윈도우의 노트패드는 UTF-8 파일에 BOM을 붙여버려서 종종 곤란한 일을 겪게 된다. 이런 혼란을 문제없이 해결하려면 노하우가 꽤 필요하다.
나는 개발을 할 때 부득이한 경우가 아니라면 BOM이 없는 UTF-8 파일을 표준으로 삼고 있다. 그리고 필요한 경우에만 예외적으로 BOM을 붙이는 것이 수월하다. 그러기 위해서는 언제 BOM이 필요하고 어디서는 BOM이 없어야 되는지 잘 알고 있어야 한다.
UTF-8에 BOM을 붙여야 하느냐, 필요 없느냐는 논쟁은 쉽게 결론이 나지 않을 것이다. 개발자가 상황에 알맞게 알아서 BOM을 붙이기도 제거하기도 해야 한다. 그래서 개발용 편집기는 BOM을 자유롭게 다룰 수 있어야 한다. 나는 개발언어나 환경에 따라서 수많은 편집기를 사용하지만 대표적인 텍스트 편집기로는 Notepad++를 사용한다. 수많은 인코딩과 BOM을 자유롭게 다루고 변환할 수 있다.
윈도우에 내장된 Notepad는 사용하지 않을 것을 추천한다. 본의 아니게 BOM이 붙어서 고생을 할 수가 있다.
추가로 빅 엔디언과 리틀 엔디언이란 용어의 유래에 대해서 알아보자.걸리버여행기를 보면 달걀 깨는 법으로 대립 중인 두 나라가 나온다. 달걀을 뾰족한 곳을 깨느냐 뭉툭한 곳을 깨느냐 논쟁을 하며 나중에는 전쟁도 하는데 여기서 뭉툭한 곳을 깨는 사람을 빅 엔디언이라고 하고 뾰족한 곳을 깨는 사람을 리틀 엔디언이라고 한다.
소프트웨어 세계도 전쟁은 하지 않았지만 두 표준이 쉽게 통일되지 않고 있다.