16. 엔디안(Endianness)과 구조체 직렬화·캐스팅 이슈

난이도 중 해설 보기 →
문제

문제 16 — 엔디안(Endianness)과 구조체 직렬화·캐스팅 이슈

면접 질문

  1. 빅 엔디안(big-endian)과 리틀 엔디안(little-endian)의 차이를 설명해보세요. 예를 들어 4바이트 정수 0x12345678이 메모리에 각각 어떻게 배치되는지 바이트 단위로 그려보세요.

  2. x86/x64, ARM 같은 대중적인 CPU 아키텍처는 보통 어떤 엔디안을 쓰나요? 반면 네트워크 프로토콜(TCP/IP)에서는 왜 "네트워크 바이트 순서"라는 별도의 표준(빅 엔디안)을 정해두었을까요? htons/htonl/ntohs/ntohl 같은 함수는 어떤 문제를 해결하나요?

  3. C/C++에서 구조체를 통째로 memcpy하거나 포인터 캐스팅으로 바이트 스트림에서 곧바로 읽어들이는(예: Packet* p = reinterpret_cast<Packet*>(buffer);) 방식은 어떤 위험을 안고 있나요? 엔디안 문제 외에 어떤 다른 문제(정렬/패딩 등)와 얽히는지도 설명해보세요.

응용 시나리오

한 게임 개발자가 클라이언트-서버 간 통신 프로토콜을 다음과 같이 설계했습니다.

struct PlayerMovePacket {
    uint16_t packetType;
    uint32_t playerId;
    float    posX;
    float    posY;
    uint16_t sequenceNumber;
};

// 송신 측: 구조체를 통째로 복사해 그대로 전송
void SendPacket(const PlayerMovePacket& pkt) {
    send(socket, reinterpret_cast<const char*>(&pkt), sizeof(pkt), 0);
}

// 수신 측: 받은 바이트를 구조체 포인터로 캐스팅해서 바로 사용
void OnReceive(char* buffer, int len) {
    PlayerMovePacket* pkt = reinterpret_cast<PlayerMovePacket*>(buffer);
    UpdatePlayerPosition(pkt->playerId, pkt->posX, pkt->posY);
}

이 코드는 개발자의 개인 PC(x64, 리틀 엔디안)에서 클라이언트와 서버를 모두 띄워 테스트할 때는 완벽하게 동작했습니다. 그런데 서버를 다른 CPU 아키텍처(예: 네트워크 장비에 내장된 빅 엔디안 프로세서)로 이전하거나, 클라이언트가 다른 컴파일러/플랫폼에서 빌드되자 좌표가 말도 안 되는 값으로 깨지는 문제가 발생했습니다.

  • 이 코드에 잠재된 문제를 엔디안 관점과 구조체 정렬(패딩) 관점 두 가지로 나누어 진단해보세요. 각각이 왜 "내 PC에서는 항상 잘 되는데 다른 환경에서 깨지는" 형태로 나타나는지 설명해보세요.
  • 이런 문제를 근본적으로 피하기 위해 실무에서 흔히 쓰는 직렬화 방식(수동 바이트 단위 인코딩, #pragma pack, 혹은 FlatBuffers/Protobuf 같은 직렬화 라이브러리 사용 등)을 최소 두 가지 이상 제시하고 각각의 트레이드오프를 설명해보세요.
답안 작성
내 답안 · 자동 저장

직접 답을 작성한 뒤, 위 해설 보기에서 모범답안과 대조하세요.