티스토리 뷰

심화

엔디안(Endian)

Just4Fun 2016. 4. 23. 14:31

이번 글에서는 엔디안(Endian)에 대해서 간단히 설명하도록 하겠다.

이미 엔디안이 무엇인지 알고 있을 수도 있고, 들어본적은 있지만 정확히 무엇인지 모르고 있을 수도 있고, 첨 들어보는 경우도 있을수 있겠다.

엔디안이라는 단어는 "걸리버 여행기"에서 처음 나왔다.  소인국 사람들 중에 달걀을 깰때 뭉툭한 곳(Big-Endian)부터 깨는 사람들이 있는 반면, 뾰족한 곳(Little-Endian)부터 깨는 사람들이 있어서 서로 자신의 방법이 맞다고 주장하는 글에서 유래되었다.

이런 상황이 컴퓨터 분야에서도 재현 되었다.

그럼 컴퓨터에서의 엔디언이 무엇인지 예를 들어 설명하도록 하겠다.

wxyz라는 숫자가 있다고 가정하자.  이 숫자가 십진수라면 w는 천의 자리 수가 되고, x는 백의 자리, y는 십의 자리, z는 일의 자리 숫자가 될것이다.  w천 x백 y십 z라고 읽을수 있겠다.  만약 w,x,y,z가 각각 한 바이트 값이고 헥사 값이라면 w는 2^24 자리가 되고 x는 2^16, y는 2^8 자리가 될 것이다.

w,x,y,z를 각각 하나의 박스에 넣고 그것들을 하나씩 위로 쌓아 올리게 되면 다음 두가지 경우가 나올 것이다.

위의 그림처럼 낮은 자리숫자가 아래에 오는것을 'little-endian'방식이라 하고, 큰자리 숫자가 아래에 놓는 방식을 'big-endian' 방식이라고 한다.  그래서 뭐 어쨌다는 건가?

문제는 여기에 주소를 할당하게 되면 조금 골치아픈 일이 생기게 된다.  우선 위의 그림만 놓고 보면 little-endian 방식이 조금 더 모양이 좋아보이지만 컴퓨터에서처럼 모든 것이 주소를 가지게 되면 상황이 달라지게 된다.

wxyz라는 데이터가 0x100에 놓이게 된다면 little-endian의 경우 0x100에 'z'가 들어가게 되고 차례로 y, x, w 순서대로 주소값을 가지게 된다.

Big-endian의 경우에는 0x100번지에 w가 할당되고 차례로 x,y,z 순서로 주소값을 가지게 된다.

이제 주소에 쓰여진 값들을 차례로 읽어 보면 little-endian방식으로는 z,y,x,w가 되고 big-endian 방식은 w,x,y,z가 된다.  주소 개념을 도입하면 little-endian 방식보다는 big-endian 방식이 더 편하게 보인다.

실제 포인터를 적용해보면 확실한 차이를 알수 있다.

만약 두바이트 포인터를 이용해서 0x100부터 읽어 보면 little-endian은 'yz','wx'가 읽히게 된다.  Big-endian은 'wx','yz'의 값으로 읽힌다.

만약 한바이트 포인터를 이용해서 읽어 보면 little-endian은 'z','y','x','w'순으로 읽히게 된다.  Big-endian 방식은 'w','x','y','z'로 읽힌다.

Little-endian의 경우는 포인터 변환이 될때마다 읽어 오는 순서가 바뀌게 된다.  다른 말로 Swap 되었다고 표현한다.  그러나 big-endian의 경우는 포인터 크기에 상관없이 항상 동일한 순서로 값들이 읽히게 된다.  이것만 놓고 보면 big-endian이 훨씬 좋아 보이게 된다.  특히 통신에 있어서는 big-endian방식이 유리한 점이 많아서 대부분 big-endian 방식으로 규격을 정의하는 경우가 많다.  이런 경우 little-endian방식의 CPU들은 big-endian 방식에 맞게 데이터 순서를 바꾸어주어야 하는 불편함이 따른다.

그러나 연산에 있어서는 big-endian 보다는 little-endian 방식이 유리하므로 딱히 어느쪽이 좋은 방식이라고 할수는 없다.

대표적인 little-endian 방식의 CPU로는 Intel의 x86 계열과, ARM 계열의 CPU들이다.  Big-endian의 대표적인 CPU는 PowerPC 계열이다.  MIPS의 경우는 프로그램이 시작될때 어떤 방식을 사용할것인지 설정하게 되면 little과 big을 선택할 수 있는 구조를 가지고 있다.

AVR은 little-endian방식으로 되어 있다.

다음 예제를 실행해 보면 little-endian이 어떻게 동작되는지 알 수 있다.

위의 코드를 실행시켜 보면 다음과 같은 결과를 얻을 수 있다.

data라는 4바이트 변수를 선언하고 그 값을 0x12345678로 설정하였다.  이 변수는 0x8F0의 주소에 할당되어 있는것으로 나온다.

이 주소를 각각 4바이트, 2바이트, 1바이트 포인터로 지정한 다음 그 값을 출력하였더니 AVR은 little-endian 방식으로 동작되는 것을 볼 수 있다.


주변 장치에서 SPI나 I2C, 혹은 UART를 통해서 데이터를 읽어 왔는데 그 값이 순서가 뒤집혀 있다면 서로 다른 endian으로 동작 되었을 수가 있으므로 서로 약속을 하든가 아니면 big-endian방식에 맞추든가 하여야 한다.


Endian 이야기와는 조금 무관하지만 다음과 같은 내용을 알고 있으면 임베디드 시스템을 하는데 있어서 도움이 될 것이다.

예를 들어 보내는 쪽에서는 분명히 0x12345678을 보냈다.  그런데 데이터를 받아보니 0x2468ACF0 였다.  완전히 엉뚱한 값처럼 보이지만 사실은 그렇지 않다.  두 값을 바이너리로 표시하면 뭔가 알 수 있게 된다.

0x12345678를 바이너리로 표현하면 '0001 0010 0011 0100 0101 0110 0111 1000'이 된다.

0x2468ACF0을 바이너리로 표현하면 '0010 0100 0110 1000 1010 1100 1111 0000'이 된다.

위의 바이너리 값들을 자세히 비교해 보면 한비트값만큼 쉬프트된것을 볼 수 있다.  실제로 데이터 통신을 하다보면 이렇게 데이터가 수신되는 경우가 있다.  이렇게 되는 이유는 보내는 쪽에서나 받는 쪽에서 한 비트값이 밀려서 들어오거나 한 비트가 잃어버리는 경우가 있기 때문이다.  그 원인은 다양하지만 어쨋든 한 비트값이 밀려서 들어오기 때문에 완전히 통신이 안되는 것은 아니라고 봐야 된다.

입문편 UART글에서도 설명하였지만 Serial 통신을 할 때 한 바이트 값안에서도 MSB를 먼저 내 보낼지, LSB를 먼저 내보느냐에 따라 그 결과가 달라진다.  데이터를 수신하면 전혀 엉뚱한 값으로 나올것이다.  심한 경우는 바이트 순서도 바뀌었을 뿐더러 비트순서도 뒤바뀌는 경우도 발생할 수 있다.  이럴때 바이너리로 변환한 후 자세히 비교해 보면 순서가 반대로 되어 있는 것을 찾아 볼 수 있게 되는것이다.

이렇게 몇개의 경우에서처럼 통신에 있어서 데이터가 송수신은 되는것 같은데 그 값이 다르게 나오면 반드시 바이너리로 변환해 보고 순서를 비교해 보기 바란다.  의외로 쉽게 문제를 해결할 수 있게 되므로 그냥 안된다고 하지말고 조금의 여유를 가지고 차근차근 문제를 해결하기 바란다.

 

엔디안과 bit order와 관련된 내용이 ON HOLY WARS AND A PLEA FOR PEACE에 잘 나와 있으므로 한번쯤 읽어 보기 바란다.


심화 과정 목차

'심화' 카테고리의 다른 글

random 함수  (4) 2016.06.12
EABI(Embedded Application Binary Interface)  (0) 2016.04.23
변수는 여기에!  (6) 2016.04.23
변수는 어디에?  (1) 2016.04.20
심화 과정 목차  (0) 2016.02.16
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함