우리는 보통 글을 읽을 때는 습관적으로 왼쪽에서 오른쪽으로 글을 읽어 나간다. 사실 이 방식은 절대적인 것은 아니며 관습에 의한 것이다. 예전 책이나 신문을 보면 글들이 위에서 아래쪽으로 쓰여진 것들이 많았다. 어느 순간 오늘날처럼 통일되어 세로로 쓰여진 책이나 신문은 보기 힘들지만 그런 책이 있더라도 충분히 읽을 수는 있다.(어색하긴 하겠지만)
글을 쓰거나 읽는 것을 컴퓨터의 경우로 치자면 데이터를 쓰거나 읽는 것으로 생각할 수 있다. 데이터를 쓰고 읽고 해석하는 행위는 사람이나 컴퓨터나 매한가지다. 단지 컴퓨터는 글을 표현하는 복잡한 문자 대신 0과 1 두가지 상태의 전기 신호를 기록하고 해석하는 것이다.
그런데 컴퓨터의 경우에는 데이터를 읽고 쓰는 순서를 미리 정해놔야 한다. 사람이라면 쓰여진 글이 세로로 쓰여졌거나 왼쪽에서 오른쪽으로, 또는 오른쪽에서 왼쪽으로 쓰던 웬만하면 알아내서 해석할 수 있다. (굳이 알려주지 않아도 된다.)
하지만 컴퓨터 융통성이 없는 기계라 정해진 룰 외에 다른 방식으로 읽거나 쓰지 않는다. 시스템마다 읽고 쓰는 방식이 상이하기 때문에 서로 방식이 상이한 시스템 간에 통신에 있어서 문제가 발생할 수도 있다. 오늘의 주제인 빅엔디안과 리틀엔디안이 바로 컴퓨터가 읽고 쓰는 방식을 의미하고 이것을 바이트 오더(byte order)라고 한다.
바이트 오더(byte order)
각 네모칸은 1bit를 나타내며 0과 1 둘 중에 하나의 상태를 저장할 수 있다. 8개의 bit가 모여 1byte를 이루는데 byte는 주소의 단위라는 것에 의의가 있다고 하겠다. 따라서 위와 같은 8칸의 그림은 1byte며 하나의 주소번지를 나타낸다.
그리고 이렇게 추상화된 그림에서 상위비트는 왼쪽, 하위비트는 오른쪽으로 인식하면 된다. 1492라는 수에서 천의 자리수 4가 1의 자리의 수 2보다 더 상위의 수인 것 처럼 비트 역시 왼쪽으로 부터 오른쪽으로 적어나갈 때 왼쪽에 있는 비트(수)가 더 상위의 비트(수)인 것이다.
- 주소는 byte 단위로
컴퓨터는 데이터를 나타낼 때 자료형에 따라서 몇 byte로 나타낼지 결정하게 된다. 주소의 단위가 byte이기 때문에 자료형의 크기도 byte 단위로 이루어져 있다. 1byte 자료형부터 2byte, 4byte, 8byte의 자료형들이 있는데 위 그림은 메모리 상에 1byte 자료형이 연속으로 2개 저장되어 있는 그림이다.
보통 메모리를 추상화해서 그림으로 그릴 때 왼쪽에서 오른쪽으로 갈수록 주소가 높아지게 그린다. 이쯤에서 헷갈릴 수가 있는 것이 자료형 내부의 비트의 경우 왼쪽에 있는 비트가 오른쪽에 있는 비트보다 상위 비트이기 때문이다.
그리고 2byte 이상의 자료형을 그린다면 확실히 더 혼란스러워 질 것이다.
2byte 이상의 자료형부터는 자료형 내부에서 2개 이상의 주소값을 포함한다.(참고 : cpu가 2byte 이상의 데이터를 찾을 때는 해당 데이터가 저장된 주소 중 가장 낮은 주소값을 읽는다.) 그리고 위 그림처럼 2byte 이상의 데이터에서는 낮은 주소 쪽에 있는 비트가 높은 주소 쪽에 있는 비트들보다 상위 비트가 된다는 걸 알 수 있다. (이 둘을 절대 혼동하면 안된다.)
그런데 컴퓨터가 데이터를 읽거나 쓸 때 byte 단위로 끊어서 읽고 쓴다. 문제는 데이터를 읽을 때 왼쪽에서부터 byte 단위로 끊어 읽고 쓰는 방식과 오른쪽에서 부터 byte단위로 끊어 읽고 쓰는 방식이 있다. 각각 빅엔디안 방식과 리틀엔디안 방식이다.
다시 위 그림으로 돌아가서 2byte 크기의 데이터(1101100111000111)가 빅 엔디안 방식으로 적혀 있는 것이라고 가정하자. 이는 우리가 일반적으로 생각하는 방식이다. 만약 리틀 엔디안 방식으로 저장된 데이터라면 1100011111011001 이렇게 저장되 있을 것이다. byte 단위로 끊어서 읽는 방향에 따라 저장방식이 달라지므로 이 방식을 byte order 라고 한다.
이렇게 2byte 이상의 자료형이라면 빅엔디안 방식과 리틀엔디안 방식의 저장방식에 차이가 생기고 읽을 때 또한 저장된 방식 그대로 읽어야 제대로 된 데이터를 읽을 수 있겠다.
빅 엔디안(big endian)
설명에 앞서 몇가지 짚고 넘어가려 한다. 1byte는 8bit로 0 ~ 11111111 까지의 표현이 가능하며, 이는 10진수로 0~255까지의 표현이 가능하다는 것과 동일하다. 이를 16진수로 표현하면 0x00 ~ 0xff 까지의 표현이 가능하다고 하겠다. (16진수는 앞에 0x를 붙여 표시한다.)
따라서 각 바이트 단위의 주소에는 0x00~ 0xff까지의 값이 기록될 수 있다. 설명의 편의상 16진수를 사용하여 데이터를 표현하도록 하겠다.
그리고 4byte 크기의 데이터가 있다고 가정해보겠다.
이 데이터는 0x0a 0x0b 0x0c 0x0d 라는 값을 가진다고 하자.
다음은 이 값이 cpu 레지스터에서 메모리에 저장되는 방식을 보여준다.
big endian
이 방식은 빅엔디안 방식으로 보통 우리가 메모리를 추상화 해서 그릴 때 자주 사용하는 방식이므로 쉽게 이해할 수 있다.
하지만 같은 값을 리틀 엔디안 방식으로 저장하면 다음과 같다.
리틀 엔디안(little endian)
쉽게말해 우리가 1492라는 수를 기록 할 때 리틀 엔디안 방식의 경우 2941이라고 기록하는 것과 같고 2941을 읽을 때는 오른쪽에서부터 왼쪽으로 읽어서 "일사구이" 라고 하는 것과 같다.
사실 이 방식이 사람이 보기에는 부자연 스럽고 비효율적으로 보일지 몰라도 장단점이 있다. 이에 대한 내용은 위키 백과에 자세히 설명하는데 포인터를 이해하고 있다면 무슨 내용인지 짐작이 갈 것이다.(빅엔디안과 리틀엔디안의 장단점)
마지막으로 bit 순서에 대해 혼동하는 분들이 있을지 몰라 짧게 언급하고 끝내려 한다.
모든 데이터는 바이트(byte) 단위로 읽고 쓰기를 하는데 2byte 이상의 데이터라면 byte order에 따라서 데이터의 읽고 쓰는 방식이 달라진다. 따라서 각 byte 내에서 bit 순서는 달라지는 것은 아니니 주의하도록 하자.