공룡호가 사는 세상 이야기

엔디안 방식에 구애 받지 않는 C코드 작성하기
http://www.ibm.com/developerworks/kr/library/au-endianc/


big-endianlittle-endian은 메모리에 저장된 바이트들의 순서를 말하는데, 빅엔디안은 큰 쪽(바이트 열에서 가장 큰 값)이 먼저 저장되는 순서이며, 리틀 엔디안은 작은 쪽(바이트 열에서 가장 작은 값)이 먼저 저장되는 순서이다. 예를 들면 빅 엔디안 시스템에서는 16진수 "4F52"를 저장공간에 "4F52"라고 저장할 것이다.(만약 4F가 1000번지에 저장되었다면 52는 1001번지에 저장) 반대로, 리틀 엔디안 시스템에서는 거꾸로 "524F"로 저장된다.

리틀 엔디안을 사용하는 대표적인 CPU는 Intel 계열 CPU이며, 빅 엔디안을 사용하는 가장 대표적인 CPU는 Sparc 계열 CPU이다. 즉, 사용하려는 시스템 CPU의 엔디안 방식에 따른 호환성의 문제가 발생할 수 있게 되는데, 아키텍처, 프로세서, 네트워크 스택, 통신 프로토콜은 모두 특정한 시점에서 엔디안 방식을 정의해야 하는데, 엔디안 방식이 코드에 영향을 미치는 경우, 런타임시 엔디안 방식을 판별하는 방법, 코드에서 바이트 순서를 뒤집어 엔디안 방식에 구애 받지 않는 방법을 알아보자.

예제 : 엔디안 방식을 모르고 프로그램을 작성할 때 발생하는 위험

#include <stdio.h>
#include <string.h>

int main (int argc, char* argv[]) {
    FILE* fp;

    /* 예제 자료 구조 */
    struct {
        char one[4];
        int  two;
        char three[4];
    } data;

    /* 예제 자료 구조를 채운다. */
    strcpy (data.one, "foo");
    data.two = 0x01234567;
    strcpy (data.three, "bar");

    /* 자료 구조를 파일에 쓴다. */
    fp = fopen ("output", "wb");
    if (fp) {
        fwrite (&data, sizeof (data), 1, fp);
        fclose (fp);
    }
}

위 코드는 모든 시스템에서 문제 없이 컴파일이 되나, 엔디안 방식에 따라 결과는 크게 다르다.(hexdump)

빅 엔디안 (hexdump -C)

00000000  66 6f 6f 00 12 34 56 78  62 61 72 00              |foo..4Vxbar.|
0000000c

리틀 엔디안 (hexdump -C)

00000000  66 6f 6f 00 78 56 34 12  62 61 72 00              |foo.xV4.bar.|
0000000c

이처럼, 엔디안 방식을 고려하지 않은 코드는 예상치 못한 곳에서 복병을 만날 수 있다.
엔디안 방식이 코드에 영향을 미치는 경우, 런타임 시 엔디안 방식 판별, 네트웍 바이트 순서, 바이트 순서 뒤집기 등으로 구성된 재미있는 기사였다.

요즘 SPARC장비들과 매일 씨름을 하고 있다 보니, 관심이 가지 않을 수 없었다. 미션 크리티컬한 업무가 운영중인 시스템들을 다루다 보니 요즘은 특히나 더 조심스러워 진다. 프로그래머도 마찬가지가 아닐까? 플랫폼이 어떤 엔디안 방식을 사용하든 실패하지 않는 코드를 구현하는 것 또한 프로그래머의 몫이리라.