[CSAPP] 비트와 바이트: 컴퓨터는 어떻게 숫자와 문자를 저장하고 해석하는가?

1. 문제 제기 (Introduction & Problem Statement)

  • 관찰 현상 또는 질문:
    컴퓨터는 모든 정보를 0과 1의 나열인 '비트(bit)'로 저장합니다. 그렇다면 어떻게 동일한 비트 패턴이 어떤 경우에는 양수 65,535로, 다른 경우에는 음수 -1로 해석될 수 있을까요? 또한, int 타입의 숫자 0x01234567을 메모리에 저장할 때, 왜 어떤 시스템은 67 45 23 01 순서로 저장하고 다른 시스템은 01 23 45 67 순서로 저장할까요?

  • 탐구 목표:
    본 아티클에서는 컴퓨터 정보 저장의 가장 기본적인 단위인 비트, 바이트, 워드의 개념을 알아봅니다. 나아가 정수를 표현하는 방식(부호 없는 정수, 2의 보수), 바이트 순서 규칙(리틀 엔디안, 빅 엔디안), 그리고 데이터 타입 변환 시 발생하는 규칙(확장, 자르기)을 분석하여, 컴퓨터가 데이터를 어떻게 저장하고 해석하는지에 대한 근본 원리를 탐구하는 것을 목표로 합니다.


2. 기술 분석 및 핵심 원리 (Technical Deep Dive)

2-1. 정보의 기본 단위: 비트, 바이트, 워드

컴퓨터의 모든 정보는 비트(bit)로 저장되지만, 개별 비트를 다루는 것은 비효율적입니다. 따라서 비트를 8개씩 묶은 바이트(Byte)를 주소 지정이 가능한 최소 메모리 단위로 사용합니다.

  • 가상 주소 공간 (Virtual Address Space): 프로그램의 관점에서 메모리는 거대한 바이트 배열로 보이며, 각 바이트는 고유한 '주소'로 식별됩니다.
  • 16진수 표현: 2진수 비트 패턴은 길고 가독성이 떨어지므로, 4비트를 한 자리로 표현하는 16진수(0-9, A-F)를 주로 사용합니다.
  • 워드 (Word): 프로세서가 한 번에 처리할 수 있는 데이터의 기본 크기입니다. 워드 크기는 가상 주소 공간의 최대 크기를 결정합니다.
    • 32비트 워드: 최대 (2^{32})바이트 (4GB)의 주소 공간.
    • 64비트 워드: 최대 (2^{64})바이트 (16EB)의 주소 공간.

2-2. 바이트 순서의 규칙: 리틀 엔디안 vs. 빅 엔디안

int와 같이 여러 바이트로 구성된 데이터를 메모리에 저장할 때, 바이트를 배열하는 순서에 대한 두 가지 규칙이 존재합니다. 데이터의 주소는 항상 가장 작은 주소의 바이트를 가리킵니다.

예시: int 변수 x = 0x01234567를 주소 0x100에 저장하는 경우

구분 주소 0x100 주소 0x101 주소 0x102 주소 0x103 주요 사용처
빅 엔디안 (Big-Endian) 01 23 45 67 Oracle DB, 네트워크 프로토콜
리틀 엔디안 (Little-Endian) 67 45 23 01 Intel, ARM 프로세서

빅 엔디안은 가장 중요한 바이트(Most Significant Byte, MSB)를 가장 낮은 주소에 저장하며, 리틀 엔디안은 가장 덜 중요한 바이트(Least Significant Byte, LSB)를 가장 낮은 주소에 저장합니다.

2-3. 정수 표현법: 부호 없는 수와 2의 보수

C와 같은 언어에서는 동일한 비트 패턴이라도 타입을 어떻게 선언하느냐에 따라 값이 다르게 해석됩니다.

  • 부호 없는 정수 (Unsigned):

    • 이진수 표현법을 그대로 값으로 변환합니다(B2U: Binary to Unsigned).
    • 모든 비트가 양의 가중치를 가지며, 0과 양수만을 표현합니다.
  • 부호 있는 정수 (Signed - 2의 보수):

    • 2의 보수(Two's Complement) 방식을 사용합니다(B2T: Binary to Two's Complement).
    • 최상위 비트(MSB)를 부호 비트로 사용하며, 이 비트는 음의 가중치를 갖습니다.
    • 장점: 덧셈, 뺄셈 등 산술 연산을 위한 하드웨어를 부호 없는 정수와 공유할 수 있어 매우 효율적입니다.
    • 특징: 표현 가능한 음수 범위가 양수 범위보다 하나 더 넓은 비대칭 구조를 가집니다 (예: 4비트에서 -8 ~ +7).

2-4. 데이터 타입 변환의 규칙

서로 다른 크기의 데이터 타입 간에 값을 변환할 때, 값의 왜곡을 막기 위한 명확한 규칙이 적용됩니다.

변환 종류 설명 규칙
확장 (작은 타입 → 큰 타입) 데이터의 값을 유지하면서 비트 수를 늘립니다. 부호 없는 수: 남는 상위 비트들을 0으로 채웁니다 (제로 확장).
부호 있는 수: 기존의 부호 비트를 복사하여 상위 비트들을 채웁니다 (부호 확장).
축소 (큰 타입 → 작은 타입) 비트 수를 줄입니다. 상위 비트들을 그대로 버립니다 (자르기). 이 과정에서 값과 부호가 모두 변경될 수 있으며, 정보 손실이 발생합니다.

signedunsigned 캐스팅:
C 언어에서 signedunsigned 타입을 서로 변환하면, 내부 비트 패턴은 그대로 유지된 채 해석 방식만 바뀝니다. 예를 들어 16비트 시스템에서 -1(signed)은 비트 패턴 1111111111111111을 가지며, 이를 unsigned로 해석하면 65,535가 됩니다. 이러한 암묵적 변환은 프로그래밍 시 예기치 않은 버그의 원인이 될 수 있습니다.


3. 결론 및 고찰 (Conclusion & Takeaways)

  • 핵심 요약:

    • 컴퓨터의 모든 정보는 비트로 저장되며, 바이트 단위로 주소가 지정되고, 워드 단위로 처리됩니다.
    • 데이터의 해석은 엔디안(바이트 순서), 타입(부호 유무), 비트 수(크기)라는 문맥에 따라 결정됩니다.
    • 2의 보수 표현법은 산술 연산 하드웨어의 효율성 때문에 현대 컴퓨터에서 부호 있는 정수의 표준으로 사용됩니다.
  • 기술적 통찰 및 나의 생각:
    동일한 비트 패턴이 컨텍스트에 따라 전혀 다른 값으로 해석될 수 있다는 사실은, 데이터의 '표현'과 '실체'가 분리되어 있음을 명확히 보여줍니다. 엔디안 차이로 인해 네트워크 통신에서 데이터가 깨지거나, 부호 확장 규칙을 이해하지 못해 타입 변환 시 버그가 발생하는 상황은 이러한 근본 원리에 대한 이해가 얼마나 중요한지 깨닫게 합니다. 이제는 단순히 코드를 작성하는 것을 넘어, 내 코드가 각기 다른 시스템 아키텍처 위에서 어떻게 비트 수준으로 변환되고 실행될지 예측하며 프로그래밍하는 시야를 갖게 되었습니다.

  • 향후 과제 / 추가 질문:

    • 정수와 달리 부동소수점 수(float, double)는 IEEE 754 표준에 따라 어떻게 표현되며, 어떤 정밀도 문제를 가질 수 있는가?
    • 엔디안 차이가 실제로 문제를 일으키는 네트워크 프로그래밍이나 파일 직렬화 상황에서 이를 어떻게 해결(예: htons, ntohl 함수)하는가?
    • 정수 오버플로(Integer Overflow)와 같은 데이터 표현 방식의 한계로 인해 발생하는 보안 취약점에는 어떤 것들이 있으며, 어떻게 방어할 수 있는가?

4. 참고 자료 (References)

  • (학습 내용의 기반이 된 개인 학습 노트)
  • Computer Systems: A Programmer's Perspective (CSAPP)