[시스템프로그래밍] Data Representation - number, data storing, data types, byte ordering

 

데이터 표현: 컴퓨터가 정보를 저장하고 처리하는 방법

컴퓨터 과학에는 데이터 표현(Data Representation)이라는 fundamental한 개념이 자리 잡고 있다. 우리가 일상생활에서 사용하는 텍스트, 숫자, 이미지, 영상 등 모든 정보는 컴퓨터 내부에서 특정한 방식으로 표현되고 저장되며 처리된다. 이러한 데이터 표현 방식을 이해하는 것은 시스템 프로그래밍을 비롯한 컴퓨터 시스템 전반에 대한 깊이 있는 이해를 위한 첫걸음이다.


숫자의 표현: 이진수, 십진수, 십육진수

우리가 흔히 사용하는 십진수는 0부터 9까지의 열 가지 기호를 사용하는 반면, 컴퓨터는 이진수 (Binary)라는 0과 1 두 가지 기호만을 사용하여 모든 데이터를 표현한다. 이는 컴퓨터 내부의 전자 회로가 두 가지 상태 (켜짐/꺼짐, 높음/낮음 전압)를 갖는 데 기반한다.

Binary representation


하지만 bit의 긴 이진수열은 사람이 이해하고 다루기에 불편하기 때문에, 프로그래밍이나 컴퓨터 구조를 설명할 때 이진수를 간결하게 표현하기 위해 십육진수 (Hexadecimal)가 자주 사용된다. 십육진수는 0부터 9까지의 숫자와 A부터 F까지의 영문자를 사용하여 0부터 15까지의 값을 나타낸다.

  • 컴퓨터 내부는 이진수를 사용하여 모든 데이터를 처리한다.
  • 프로그래머는 이진수를 더 쉽게 이해하고 표현하기 위해 십육진수를 자주 활용한다.
  • 십진수는 인간이 일상적으로 사용하는 숫자 체계이다.
Hex / Decimal / Binary


데이터 저장의 기본 단위: 바이트 (Byte)와 워드 (Word)

컴퓨터에서 데이터가 저장되는 가장 기본적인 단위는 바이트 (Byte)이며, 일반적으로 8비트(bit)로 구성된다. 바이트는 하나의 문자 (character)를 표현하기에 충분한 크기이며, 메모리의 주소 지정 단위로도 사용된다.

워드 (Word)는 특정 컴퓨터 아키텍처(Computer Architecture)에서 한 번에 처리할 수 있는 데이터의 크기를 나타낸다. 워드의 크기는 시스템에 따라 다르며, 32비트 또는 64비트 시스템이 일반적이다. 워드 크기는 CPU가 메모리에서 데이터를 읽고 쓰는 효율성에 영향을 미친다.

Byte-oriented memory organization


한편, 프로그램은 위와 같은 가상 메모리의 특정 영역을 할당받는다.
가상 주소(Virtual address)는 바로 이 가상 메모리 공간 내에서 각 메모리 위치에 할당되는 주소를 의미한다. 프로그램의 크기 자체는 굉장히 클지라도 실제로 프로세스가 사용하는 메모리는 작다는 점에서 등장한 개념이다.
각 프로세스는 독립된 가상 주소 공간을 갖고, 실제 해당 주소에서 데이터를 읽고 쓸 때만 MMU(Memory Management Unit)을 통해 물리 주소로 바꾸어 프로그램을 작성하고 실행한다.


가상 주소의 주요 특징 및 이점은 다음과 같다:

  • 물리적 메모리로부터의 추상화: 프로그래머는 실제 물리 메모리의 구성이나 크기에 대해 신경 쓰지 않고, 연속적이고 큰 가상 주소 공간을 사용하는 것처럼 프로그래밍할 수 있다.
  • 프로세스 간 독립성 및 보호: 각 프로세스는 독립된 가상 주소 공간을 가지므로, 한 프로세스가 다른 프로세스의 메모리 영역에 함부로 접근하는 것을 방지하여 시스템의 안정성을 높인다.
  • 물리 메모리 관리의 효율성: 가상 메모리 시스템은 실제로 사용되는 메모리 영역만 물리 메모리에 로드하고, 나머지는 보조 기억 장치에 저장하여 물리 메모리의 사용 효율성을 높인다.
  • 주소 공간 확장: 물리 메모리의 용량보다 더 큰 프로그램을 실행할 수 있도록 한다.

이러한 가상 메모리 시스템 덕분에 인터넷 창을 여러개 띄우는 등 여러 프로세스가 동시에 시스템에서 동작할 수 있다.


다양한 데이터 타입 (Data Types)

프로그래밍 언어에서는 다양한 종류의 데이터를 효율적으로 관리하기 위해 여러 데이터 타입(Data Type)을 제공한다. 각 데이터 타입은 메모리 내에서 차지하는 크기와 데이터를 해석하는 방식이 다르다. C 언어에서 흔히 사용되는 데이터 타입과 그 일반적인 크기는 다음과 같다:

  • char: 1 바이트 (문자)
  • short: 2 바이트 (짧은 정수)
  • int: 4 바이트 (정수)
  • long: 4 바이트 (일반적으로 32비트 시스템), 8 바이트 (일반적으로 64비트 시스템) (긴 정수)
  • long long: 8 바이트 (매우 긴 정수)
  • float: 4 바이트 (단정밀도 부동 소수점)
  • double: 8 바이트 (배정밀도 부동 소수점)
  • long double: 8, 10 또는 16 바이트 (확장 정밀도 부동 소수점)
  • pointer: 4 바이트 (32비트 시스템), 8 바이트 (64비트 시스템) (메모리 주소)

특히 포인터 (Pointer) 타입은 메모리 주소를 값으로 저장하는 특별한 데이터 타입이다. 포인터를 통해 프로그램은 특정 메모리 위치에 직접 접근하여 데이터를 읽고 쓸 수 있다.


바이트 순서 (Byte Ordering): Big Endian vs. Little Endian

여러 바이트로 이루어진 데이터를 메모리에 저장하는 방식에는 Big EndianLittle Endian 두 가지 주요 방식이 있다. 이는 바이트 순서(Byte Ordering) 또는 엔디안(Endianness) 문제로 불린다.

  • Big Endian: 데이터의 최상위 바이트 (Most Significant Byte, MSB)부터 시작하여 순서대로 메모리에 저장하는 방식이다. 이는 우리가 숫자를 읽는 방식과 유사하다.
  • Little Endian: 데이터의 최하위 바이트 (Least Significant Byte, LSB)부터 시작하여 역순으로 메모리에 저장하는 방식이다.

예를 들어, 16진수 값 0x12345678을 4바이트 메모리에 저장한다고 가정했을 때:

  • Big Endian 방식은 다음과 같이 저장한다: 0x12 | 0x34 | 0x56 | 0x78 (메모리 주소 증가 방향)
  • Little Endian 방식은 다음과 같이 저장한다: 0x78 | 0x56 | 0x34 | 0x12 (메모리 주소 증가 방향)


이러한 바이트 순서 차이는 서로 다른 아키텍처를 가진 시스템 간에 데이터를 교환할 때 심각한 문제를 야기할 수 있다. 한 시스템에서 저장한 멀티바이트 데이터를 다른 시스템에서 반대 순서로 해석하면 전혀 다른 값이 되기 때문이다. 네트워크 통신이나 파일 공유 시 이러한 Endianness를 고려해야 데이터 해석 오류를 방지할 수 있다.

IA32(32bit, Little Endian), x86-64(65bit, Little Endian) , Sun(32bit, Big Endian)


왜 Little Endian을 주로 이용하는가?

Little Endian 방식이 특정 아키텍처(특히 Intel 계열)에서 주로 사용되는 데에는 몇 가지 역사적, 기술적 이유가 있다. 명확한 단일 이유는 아니지만, 주로 다음과 같은 요인들이 복합적으로 작용한 것으로 알려져 있다.

  1. 산술 연산의 편의성: Little Endian 방식은 메모리 주소 0번지부터 시작하여 숫자의 크기가 커지는 방향으로 바이트를 저장한다. 이는 덧셈이나 곱셈 연산 시 LSB부터 처리하는 방식과 자연스럽게 맞아떨어져, 캐리(carry) 처리 등을 효율적으로 만들 수 있다. 특히, 주소 0번지에 LSB가 위치하므로, 1바이트, 2바이트, 4바이트 등 다양한 크기의 정수를 동일한 메모리 주소에서 읽어올 수 있다는 장점이 있다.
  2. Intel 아키텍처의 영향: Intel x86 계열 프로세서가 Little Endian 방식을 채택하면서, PC 시장을 중심으로 Little Endian이 널리 사용되게 되었다. 시장 점유율이 높은 아키텍처의 영향으로 인해 소프트웨어 및 주변 생태계 역시 Little Endian에 맞춰지는 경향이 있었다.
  3. 구현의 단순성: 일부 아키텍처 설계자들은 Little Endian 방식이 하드웨어 구현을 더 단순하게 만들 수 있다고 판단했다.

물론 Big Endian 방식 역시 네트워크 프로토콜(Network Byte Order는 Big Endian) 등 특정 분야에서 여전히 중요한 역할을 수행하고 있으며, 각 방식은 나름의 장단점을 가지고 있다.


부호 있는 정수의 표현: 2의 보수 (Two's Complement)

컴퓨터 내부에서 부호 있는 정수(Signed Integer)를 표현하는 가장 일반적인 방식은 2의 보수 (Two's Complement)이다. 2의 보수 방식은 다음과 같은 단계로 음수(Negative Number)를 표현한다:

  1. 양수의 이진수 표현을 구한다.
  2. 각 비트를 반전시킨다 (0은 1로, 1은 0으로). (이를 1의 보수(One's Complement)라고 한다).
  3. 결과에 1을 더한다. (이것이 2의 보수 표현이다).

예를 들어, 8비트에서 -5를 2의 보수로 표현하는 과정은 다음과 같다.

  1. +5의 이진수 표현: 00000101
  2. 1의 보수: 11111010
  3. 2의 보수: 11111011

2의 보수 방식은 다음과 같은 중요한 장점을 제공한다:

  • 덧셈과 뺄셈 연산의 통합: 양수와 음수의 덧셈 연산을 동일한 하드웨어 회로로 처리할 수 있게 해준다. 예를 들어, 5 + (-5)는 2의 보수 표현을 사용하여 이진수 덧셈을 수행하면 자동으로 0이 된다 (오버플로우 비트 제외).
  • 유일한 0 표현: 1의 보수 방식과 달리, 2의 보수 방식에서는 0이 00000000 단 하나의 표현만을 가진다.
  • 음수 표현의 효율성: 최상위 비트 (Most Significant Bit, MSB*가 부호 비트(Sign Bit) 역할을 하며 (0이면 양수, 1이면 음수), 음수를 효율적으로 표현하고 비교 연산을 수행할 수 있도록 한다.


결론

컴퓨터 내부에서 데이터가 어떻게 표현되는지를 이해하는 것은 효율적인 시스템 프로그래밍과 문제 해결 능력 향상에 필수적이다. 이진수, 바이트, 워드, 데이터 타입, 바이트 순서(Endianness), 그리고 2의 보수와 같은 핵심 개념들을 숙지함으로써 우리는 컴퓨터 시스템의 동작 방식을 더 깊이 있게 이해하고, 더 나아가 성능 최적화시스템 호환성 문제 해결에 효과적으로 접근할 수 있을 것이다.




추천글:


hyeon_B

안녕하세요! AI 기술을 이용해 더 나은 세상을 만들어 나가고 싶은 과기원생 Hyeon이라고 합니다. 저는 앞으로 인공지능 시대에는 지식을 '활용'하는 능력이 중요해질 것이라고 생각합니다. 대부분의 일들은 인공지능이 뛰어난 모습을 보이지만, 인공지능은 데이터로 부터 연관관계를 학습하기 때문에 지식들을 새로 통합해서 활용하는 능력이 부족합니다. 인공지능이 뉴턴 전에 만들어졌다면 사과가 떨어지는 이유에 대답하지 못했을 것이고, 아인슈타인 전에 만들어졌다면 중력이 어떻게 생기는지 설명하지 못했을 것입니다. 따라서 앞으로 우리는 '본질'을 탐구하고 그 본질로부터 다른 곳에 적용하며 인공지능을 현명하게 활용해야 할 것입니다. 함께 인공지능 시대를 준비합시다!

댓글 쓰기

다음 이전

POST ADS1

POST ADS 2