엔디안(Endianness)과 데이터 순서 변환 이해하기

반응형

엔디안(Endianness)

엔디안은 컴퓨터 메모리나 다른 데이터 포맷에서 다중 바이트 데이터를 메모리에 저장하거나 전송할 때, 바이트를 배열하는 방식을 말한다. 서로 다른 엔디안을 사용하는 시스템 간의 데이터 교환 시 각각의 시스템에 맞는 네트워크 바이트 순서로 변환해줘야 한다.

 

1. 빅엔디안(Big-endian)

  • 데이터를 메모리의 가장 큰 주소부터 저장하는 방식이다. (큰 단위의 바이트가 메모리의 낮은 주소에 저장됨)
    ex) '0x12345678' 은 메모리에 [12 34 56 78] 순서로 저장 -> 네트워크 프로토콜, 특히 TCP/IP 스택은 빅엔디안을 사용한다.
주소 1 | 0x12
주소 2 | 0x34
주소 3 | 0x56
주소 4 | 0x78

 

2. 리틀엔디안(Little-endian)

  • 데이터를 메모리의 가장 작은 주소부터 저장하는 방식이다. (작은 단위의 바이트가 메모리의 가장 낮은 주소에 저장됨)
    ex) '0x12345678' 은 메모리에 [78 56 34 12] 순서로 저장 -> 인텔 x86 아키텍처를 비롯한 개인용 컴퓨터에 많이 사용되는 방식
주소 1 | 0x78
주소 2 | 0x56
주소 3 | 0x34
주소 4 | 0x12
 

3. 미들엔디안(Middle-endian)

  • 위의 두 경우에 속하지 않거나, 둘 다 지원하는 경우를 미들 엔디안이라 부른다.
  • 종종 32비트 정수가 2바이트 단위로는 빅 엔디안이고 그 안에서 1바이트 단위로 리틀 엔디안인 경우에도 미들 엔디안이라 한다.
34 12 78 56
또는
56 78 12 34

 

4. 현재 사용 중인 바이트 저장 순서 확인하기

#include <stdio.h>
 
int main() {
int i;
int test = 0x12345678;
char* ptr = (char*)&test;
 
for (i = 0; i < sizeof(int); i++) {
printf("%02x", (unsigned char)ptr[i]);
}
 
return 0;
}


5. 네트워크와 엔디안 문제

네트워크 프로토콜, 특히 TCP/IP는 데이터를 빅엔디안으로 전송한다. 그렇다면, 리틀엔디안을 사용하는 호스트는 데이터를 어떻게 해석할까?

  1. 문제 발생:
    네트워크에서 데이터를 주고받을 때 송신자와 수신자가 서로 다른 엔디안을 사용한다면 데이터 순서를 바르게 해석하지 못할 수 있음
  2. 해결 방법:
    데이터를 전송할 때 **네트워크 바이트 순서(Network Byte Order)**로 변환하고, 수신자가 다시 **호스트 바이트 순서(Host Byte Order)**로 변환

6. 변환 함수 매크로

htons Host to Network Short (16비트 변환)
htonl Host to Network Long (32비트 변환)
ntohs Network to Host Short (16비트 변환)
ntohl Network to Host Long (32비트 변환)

 

 

7. 리눅스에서 엔디안 변환 매크로의 동작 원리

  • 리눅스 커널은 다양한 종류의 CPU 아키텍처(Intel, ARM 등)를 지원하고, 각각의 아키텍처는 byteorder.h 파일을 사용해 해당 CPU의 엔디안을 정의하고 있다.
  • 경로:
    • include/linux/byteorder/generic.h (공통 정의)
    • include/linux/byteorder/little_endian.h 또는 big_endian.h (엔디안별 정의)

쉽게 이해하기

  1. 리틀엔디안은 작은 주소부터 차례대로 쌓는다.
  2. 빅엔디안은 큰 주소부터 차례대로 쌓는다.
  3. 네트워크는 모두 빅엔디안을 따르고, 호스트 간의 데이터 해석을 위해 변환이 필요하다.
반응형