포스트

리틀 엔디안과 빅 엔디안

컴퓨터 과학 기초부분에서 다루는 '엔디안'이라는 개념을 다루고, 리틀 엔디안과 빅 엔디안의 차이점과 엔디안의 어원 그리고 엔디안을 신경써야하는 상황과 이유들을 간단하게 소개한다.

리틀 엔디안과 빅 엔디안

컴퓨터 과학을 공부하다보면 자연스럽게 ‘엔디안’이라는 용어를 접하게 된다. 영어로는 Endianness라고 하는데 이를 줄여서 Endian이라고 부른다. 엔디안은 컴퓨터가 0과 1로 구성된 비트를 어떻게 저장하고 다루는지를 의미한다. 다루는 방식에 따라서 리틀 엔디안(Little Endian) 혹은 빅 엔디안(Big Endian)이라고 부르고 이번 포스트에서 이들을 소개하고자 한다.

간단하게 이야기하면 컴퓨터 시스템의 바이트를 어느 방향으로 읽느냐를 기준으로 나눈다. 최상위 바이트(MSB, the Most Significant Byte)를 왼쪽으로 두냐 오른쪽으로 두냐 그 차이이다. 십진법으로 예를 들면, 12345라는 수가 있을 때 이 수를 리틀 엔디안으로 읽으면 54321로 읽힌다. 빅 엔디안은 이와는 정반대인 12345이다.

엔디안 예시

little and big endians preview

이 사진과 같이 만약 우리가 메모리 주소 0x100에 정수값(int)으로 0x1234567가 있다고 가정해보자. 총 4 바이트를 가지기 때문에 이 값은 0x100부터 0x103까지 자리를 차지할 것이다.

이 정수값의 최상위 바이트는 당연하게도 0x01이다. 빅 엔디안에선 우리가 익히 알고있는 수나열 방식 그대로 0x01234567로 저장되고 표현된다. 리틀 엔디안에선 최상위 바이트가 가장 끝으로 가서 거꾸로 표현된다. 즉, 최하위 비트(LSB, the Least Significant Byte)인 0x67이 처음으로 오게되는 방식이다.

엔디안의 어원

출처: https://en.wikipedia.org/wiki/endianness

엔디안이라는 용어의 어원은 유명한 고전 소설 조나단 스위프트의 걸리버 여행기에서 나왔다. 작중 난쟁이들이 사는 나라 소인국에서 달걀을 어느 쪽으로 깨먹는가에 대해 논쟁에 벌어진 이야기가 나온다. 알고있듯이 계란에는 뭉툭한 쪽과 뾰족한 쪽이 있는데 뭉툭한 쪽을 깨먹는 사람들을 Big Endian, 그 반대는 Little Endian이라고 칭했다. 계란의 한 쪽 끝을 의미하는 End에다가 사람을 의미하는 어미 -ian이 붙은 형태이다.

사실 달걀은 어느 쪽으로 먹던 전혀 상관은 없다. 그렇지만 컴퓨터의 경우에는 데이터를 어떤 방식으로 저장하냐에 따라서 처리하는 방식이 달라지기 때문에 꽤나 중요한 문제가 된다.

엔디안 체크법

자기의 컴퓨터가 리틀을 사용하는지 빅을 사용하는지 확인하는 데에는 여러가지 방법이 있지만 대표적으로 unsigned 값 1을 1바이트 형으로 줄여서 값을 확인하는 방법이 있다. 아래에 C언어를 이용해 이를 구현한 코드가 있다.

1
2
3
4
5
6
7
8
9
10
int main()
{
    unsigned int n = 1;
    char* c = (char*) &n;

    if (*c) { std::cout << "Little Endian"; }
    else    { std::cout << "Big Endian"; }
}

// "Little Endian" will be printed if you are using x86-64 processor

“IMAGE”

포인터를 다룰 줄 알면 쉽게 이해할 수 있는 코드이지만 그렇지 않은 사람들을 위해 설명을 간단히 덧붙이지면 이러하다.

unsigned int n에 1을 저장한다. 그리고 n의 형태를 char* 포인터 형으로 변환해주면서 강제로 4바이트를 가졌던 int n을 1바이트만 가지는 char로 변환해준다. 해당 char 주소에 1이라는 값이 있다면 해당 코드를 실행한 컴퓨터는 리틀 엔디안을 사용하고 있다는 것을 알 수 있다. 빅 엔디안을 사용한다면 0이라는 값이 있을 것이다.

엔디안으로 생기는 이슈

개발자들이 컴퓨터 시스템의 엔디안에 대해서 신경써야하는 경우는 거의 없다. 운영체제가 주로 해당 업무를 알아서 처리해주기 때문이다. 일부 상황에 엔디안이 상당히 중요한 역할을 하는데 그 예시에 대해 이야기하고자 한다.

서로 다른 컴퓨터 간의 데이터 수송신

두 컴퓨터가 서로 소통(네트워킹)하고 있다고 생각했을 때, 만약 서로 같은 엔디안 체계를 사용한다면 신경쓸 것은 전혀 없다. 하지만 서로 다른 엔디안을 사용할 때에는 이야기가 달라진다. 대표적으로 TCP/IP 프로토콜은 빅 엔디안을 사용하지만 대부분의 프로세서들은 리틀 엔디안을 사용하기에 커뮤니케이션 전에 반드시 변환 과정을 거쳐야하는 번거로움이 있다. (소켓 라이브러리를 직접 작성하는게 아니라면 이 문제 또한 개발자가 신경쓰지 않아도 된다)

포인터 변환

위에서 소개했던 엔디안 체크하는 프로그램에서도 봤듯이 어떠한 데이터 형의 사이즈를 변환하는 상황에서 엔디안 문제는 큰 영향을 끼친다. 아까와 비슷하게 변환을 시도한다고 생각해보자. 0x12345678의 값을 리틀 엔디안 시스템에선 0x78563412로 저장하게 된다. 이를 char형으로 변환하면 0x78만 남게되며 나머지 0x563412는 잘린다.

이 현상을 의도할 순 있지만 웬만한 상황에선 오버플로우같은 에러들처럼 예상치 못한 문제를 야기할 수 있는 위험요소다. 그렇기에 개발할 때에 형변환은 최대한 피해야하고 어쩔 수 없이 해야하는 경우에는 심혈을 기울여야 하는 이유가 바로 여기에 있다. 예시를 리틀 엔디안으로만 들고있지만 빅 엔디안도 마찬가지이다.

어떤 엔디안 시스템이 더 나은가?

사람들은 어떠한 것들에 순위를 매기기를 좋아한다. 그래서 리틀과 빅 엔디안 시스템 중 어느 것이 더 나은가에 대해 논쟁을 벌이는 경우가 심심치않게 생기는데(엔디안의 어원도 계란 깨는 방향을 두고 싸웠기 때문에 생겼다) 기술적으로 어느 것이 더 나은가를 두고 겨루는 것은 별 의미가 없다.

Bi Endian

최근에 나오는 프로세서들은 리틀과 빅을 모두 지원하는 Bi 엔디안을 가진다. 사용자가 직접 고르거나 OS에 의해 한 쪽으로 강제되는 방식이다. 정말 말 그대로 ‘둘 다’ 사용할 순 없기 때문이다.

프로세서 별 엔디안

가장 유명하고 많이 사용하는 인텔(지금은 아닐 수 있다)의 경우 주로 리틀 엔디안을 사용하고 IBM이나 오라클의 경우 빅 엔디안을 사용한다고 한다. 스마트폰에서 주로 사용되는 ARM 프로세서는 둘 다 지원하지만 Android와 IOS가 리틀 엔디안을 강제하면서 모바일 스마트폰 대부분은 리틀 시스템을 사용한다.

출처

endian

Endianness

What is Endianness? Big-Endian & Little-Endian

Intel®IXP4XX Product Line of Network Processors and IXC1100 Control Plane Processor: Understanding Big Endian and Little Endian Modes

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.