엔디안

엔디안이란?

엔디안은 메모리에 저장된 멀티바이트 데이터의 바이트 순서(Byte Order)를 나타내는 개념이다. 같은 데이터를 저장할 때 바이트를 어떤 순서로 배치하느냐에 따라 해석이 달라진다.

엔디안이 적용되는 데이터 타입

적용되는 데이터 타입

엔디안은 1바이트보다 큰 데이터 타입에만 적용된다:

데이터 타입크기엔디안 적용 여부
char1바이트❌ 적용 안 된다
short2바이트✅ 적용됨
int4바이트✅ 적용됨
long4바이트 (32비트) / 8바이트 (64비트)✅ 적용됨
long long8바이트✅ 적용됨
float4바이트✅ 적용됨
double8바이트✅ 적용됨
pointer4바이트 (32비트) / 8바이트 (64비트)✅ 적용됨

핵심 원리

  • 1바이트 데이터: 엔디안 문제가 없다. 바이트가 하나뿐이므로 순서가 의미가 없다.
  • 멀티바이트 데이터: 2바이트 이상의 데이터는 바이트 순서에 따라 해석이 달라진다.

엔디안의 종류

Big Endian (빅 엔디안)

바이트를 낮은 주소부터 저장하는 방식이다.

메모리 주소:  [0x1000] [0x1001] [0x1002] [0x1003]
데이터:      [  0x12] [  0x34] [  0x56] [  0x78]
            ↑ 여기서 시작
  • 사람이 읽기 쉬운 순서: 왼쪽에서 오른쪽으로 읽으면 자연스럽다.
  • 사용 예시: 네트워크 프로토콜(IP 주소 등), 일부 프로세서(ARM의 일부 모드, PowerPC 등)

Little Endian (리틀 엔디안)

바이트를 높은 주소부터 저장하는 방식이다.

메모리 주소:  [0x1000] [0x1001] [0x1002] [0x1003]
데이터:      [  0x78] [  0x56] [  0x34] [  0x12]
                                       ↑ 여기서 시작
  • 메모리 효율성: 산술연산은 하위 바이트에서 시작하기 때문에 리틀 엔디안 방식은 cpu 연산에 유리하다.
  • 사용 예시: x86/x64 아키텍처, 대부분의 개인용 컴퓨터

뒤집는 단위와 범위

뒤집는 단위: 바이트(Byte) 단위

엔디안은 바이트 단위로 뒤집힌다. 비트 단위가 아니다.

예시: 0x12345678 (4바이트 정수)

Big Endian:

메모리 주소:  0x1000  0x1001  0x1002  0x1003
바이트 값:    0x12    0x34    0x56    0x78

Little Endian:

메모리 주소:  0x1000  0x1001  0x1002  0x1003
바이트 값:    0x78    0x56    0x34    0x12

각 바이트 내부의 비트 순서는 변하지 않는다. 바이트 단위로만 순서가 바뀐다.

뒤집는 범위: 전체 데이터 타입의 크기

엔디안 변환은 데이터 타입의 전체 크기 범위에 적용된다.

2바이트 데이터 (short)

short value = 0x1234;  // 2바이트

Big Endian:

[0x12] [0x34]

Little Endian:

[0x34] [0x12]

4바이트 데이터 (int)

int value = 0x12345678;  // 4바이트

Big Endian:

[0x12] [0x34] [0x56] [0x78]

Little Endian:

[0x78] [0x56] [0x34] [0x12]

8바이트 데이터 (long long)

long long value = 0x1234567890ABCDEF;  // 8바이트

Big Endian:

[0x12] [0x34] [0x56] [0x78] [0x90] [0xAB] [0xCD] [0xEF]

Little Endian:

[0xEF] [0xCD] [0xAB] [0x90] [0x78] [0x56] [0x34] [0x12]

실제 예제

C 코드로 확인하기

#include <stdio.h>

int main() {
    int value = 0x12345678;
    unsigned char *bytes = (unsigned char *)&value;

    printf("Value: 0x%08X\n", value);
    printf("Memory layout:\n");
    for (int i = 0; i < sizeof(int); i++) {
        printf("  [%p]: 0x%02X\n", &bytes[i], bytes[i]);
    }

    return 0;
}

4바이트 int를 Little Endian으로 변환하는 toBytes 함수

#include <stdio.h>
#include <stdint.h>

void toBytes(uint32_t value, unsigned char *bytes) {
    // Little Endian: 낮은 주소부터 LSB부터 저장
    bytes[0] = (value >> 0) & 0xFF;  // LSB (0x78)
    bytes[1] = (value >> 8) & 0xFF;  // 0x56
    bytes[2] = (value >> 16) & 0xFF; // 0x34
    bytes[3] = (value >> 24) & 0xFF; // MSB (0x12)
}

int main() {
    uint32_t value = 0x12345678;
    unsigned char bytes[4];

    toBytes(value, bytes);

    printf("Value: 0x%08X\n", value);
    printf("Little Endian bytes:\n");
    for (int i = 0; i < 4; i++) {
        printf("  bytes[%d] = 0x%02X\n", i, bytes[i]);
    }

    // 출력:
    // Value: 0x12345678
    // Little Endian bytes:
    //   bytes[0] = 0x78
    //   bytes[1] = 0x56
    //   bytes[2] = 0x34
    //   bytes[3] = 0x12

    return 0;
}

엔디안이 중요한 상황

1. 네트워크 통신

네트워크 프로토콜은 **Big Endian(Network Byte Order)**을 표준으로 사용한다. 서로 다른 엔디안을 가진 시스템 간 통신 시 변환이 필요하다.

// 네트워크 바이트 순서로 변환
uint32_t host_value = 0x12345678;
uint32_t network_value = htonl(host_value);  // Host TO Network Long

2. 파일 포맷

바이너리 파일 포맷은 특정 엔디안을 가정한다. 예를 들어:

  • PNG: Big Endian
  • GIF: Little Endian
  • JPEG: Big Endian

3. 프로세서 간 데이터 공유

서로 다른 엔디안을 가진 프로세서 간 데이터를 공유할 때 변환이 필요하다.

4. 디버깅

메모리 덤프를 읽을 때 엔디안을 고려해야 올바르게 해석할 수 있다.

요약

항목설명
적용 데이터 타입1바이트보다 큰 모든 멀티바이트 데이터 타입 (short, int, long, float, double, pointer 등)
뒤집는 단위바이트(Byte) 단위 (비트 단위 아님)
뒤집는 범위데이터 타입의 전체 크기 (2바이트면 2바이트 전체, 4바이트면 4바이트 전체)
핵심 원리각 바이트 내부의 비트 순서는 변하지 않고, 바이트들의 순서만 바뀜

추가 참고사항

  • 엔디안 중립 코드 작성: 네트워크 통신이나 파일 I/O 시에는 항상 엔디안 변환 함수(htonl, ntohl 등)를 사용해야 한다.
  • 현대 시스템: 대부분의 개인용 컴퓨터는 Little Endian을 사용하지만, 네트워크 표준은 Big Endian이므로 변환이 필요하다.