Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++에서 빅 엔디안과 리틀 엔디안 값 변환하는 방법

C++에서 리틀 엔디안(Little Endian) 값을 빅 엔디안(Big Endian)으로, 혹은 그 반대로 변환하는 방법을 알아보겠습니다. 본격적인 설명에 앞서, 먼저 빅 엔디안과 리틀 엔디안이 무엇인지 간단히 살펴보겠습니다.

빅 엔디안과 리틀 엔디안이란?

시스템 아키텍처에 따라 멀티바이트(multi-byte) 데이터는 메모리에 두 가지 방식으로 저장될 수 있습니다. 상위 바이트(큰 자릿수)를 먼저 저장하는 방식을 빅 엔디안이라고 하고, 하위 바이트(작은 자릿수)를 먼저 저장하는 방식을 리틀 엔디안이라고 합니다.

예를 들어 16진수 0x12345678을 4바이트 정수로 저장한다고 가정해 보겠습니다.

  • 빅 엔디안: 12 34 56 78 — 사람이 읽는 순서와 동일하게 저장됩니다.
  • 리틀 엔디안: 78 56 34 12 — 낮은 메모리 주소부터 하위 바이트가 저장됩니다.

x86 계열 CPU는 대부분 리틀 엔디안 방식을 사용하는 반면, 네트워크 전송 표준은 빅 엔디안을 따르기 때문에 두 방식 간의 변환은 네트워크 프로그래밍에서 매우 중요한 작업입니다.

엔디안 변환 원리: 비트 시프트와 마스크 연산

32비트 정수의 엔디안을 변환하려면 1번째 바이트와 4번째 바이트, 2번째 바이트와 3번째 바이트의 자리를 서로 맞바꿔야 합니다. 이 작업은 논리 연산식만으로도 구현할 수 있습니다. 원본 값을 네 개로 복제한 뒤 각각 다음과 같이 처리하고, 결과를 모두 OR 연산으로 결합하면 바이트 순서가 뒤집힌 값을 얻을 수 있습니다.

  1. (x >> 24) — 최상위 바이트를 하위 8비트 위치로 이동
  2. ((x & 0x00FF0000) >> 8) — 두 번째 바이트를 마스크로 추출한 뒤 오른쪽으로 8비트 이동
  3. ((x & 0x0000FF00) << 8) — 세 번째 바이트를 마스크로 추출한 뒤 왼쪽으로 8비트 이동
  4. (x << 24) — 최하위 바이트를 최상위 8비트 위치로 이동

예제 코드

#include <iostream>
using namespace std;

#define SWAP_INT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) |
                       (((x) & 0x0000FF00) << 8) | ((x) << 24))

void memory_represent(char *value, int n) {
    for (int i = 0; i < n; i++)
        printf(" %.2x", value[i]);
}

int main() {
    unsigned int x = 0x12345678;
    unsigned int y;

    cout << "리틀 엔디안 값:";
    memory_represent((char*)&x, sizeof(x));
    cout << endl;

    y = SWAP_INT32(x);
    cout << "변환 후 빅 엔디안 값:";
    memory_represent((char*)&y, sizeof(y));
    cout << endl;

    return 0;
}

함수 memory_represent()는 변수가 실제로 메모리에 저장된 바이트 값을 16진수 형태로 하나씩 출력하여, 엔디안 변환 전후의 차이를 눈으로 확인할 수 있게 해 줍니다.

실행 결과

리틀 엔디안 값: 78 56 34 12
변환 후 빅 엔디안 값: 12 34 56 78

SWAP_INT32 매크로를 통해 각 바이트의 위치가 정확히 뒤바뀐 것을 확인할 수 있습니다. 참고로 실무에서는 위와 같은 매크로 대신 POSIX/윈도우 소켓 API에서 제공하는 htonl(), ntohl(), htons(), ntohs() 함수를 사용해 호스트 바이트 순서와 네트워크 바이트 순서(빅 엔디안)를 손쉽게 변환할 수도 있습니다. 다만 이러한 내부 동작 원리를 이해해 두면 임베디드 환경이나 파일 포맷 파싱 등 다양한 상황에서 큰 도움이 됩니다.