> For the complete documentation index, see [llms.txt](https://wonjoon.gitbook.io/joons-til/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wonjoon.gitbook.io/joons-til/c/.exe-part1.md).

# .exe 부터 프로그램 실행까지 part1

## 0장. 컴퓨터의 큰 그림

### 0. 이 장에서 배우는 것 (3줄 요약)

* 컴퓨터는 **하드웨어 → 펌웨어 → 운영체제(OS) → 응용프로그램**의 4층 케이크 구조다.
* 컴퓨터가 다루는 정보는 결국 **비트(bit)**, 그리고 **0과 1로 표현되는 전기 신호**다.
* 이 자료에서 추적할 ".exe 더블클릭"이라는 사건은 이 4층 구조 전체에 걸쳐 일어난다.

***

### 1. 비유 — 컴퓨터는 거대한 음식점

컴퓨터를 "거대한 음식점"이라고 상상해본다.

* **주방 = 하드웨어(Hardware)**: 진짜 일이 일어나는 곳. 가스레인지(CPU), 도마(메모리), 냉동창고(디스크)가 모여 있다. 손이 직접 닿으면 위험하다.
* **매니저 = 운영체제(OS)**: 주방을 손님이 직접 못 만지게 막고, 주문을 받아 주방에 전달하고, 자리가 모자라면 누구를 먼저 받을지 정한다. 또한 모든 식기·자리·재료를 자기가 장부로 관리한다.
* **펌웨어 = 주방 매뉴얼**: 가스를 어떻게 켜고, 화구를 어떤 순서로 점검하는지 적힌 코팅된 종이. 음식점이 문을 여는 순간 매니저보다 먼저 읽힌다.
* **손님 = 응용프로그램(Application)**: "김치찌개 하나요" 같은 요청을 매니저에게 한다. 주방에는 절대 직접 들어가지 못한다.
* **메뉴판의 카테고리 = 파일 확장자**: 어떤 손님이 어떤 카테고리의 음식을 시키는지 표시.
* **주문서 한 장 한 장 = 프로세스(Process)**: 손님 한 명이 들어와 받은 주문서. 같은 메뉴를 시켜도 주문서는 별개로 발급된다.

#### 주문이 주방까지 가는 길

손님(응용프로그램)이 "김치찌개 하나요"라고 외친다고 해서 그 소리가 그대로 주방까지 가는 건 아니다. \
매니저(OS)가 들어주고, 자기 양식의 주문서로 옮겨 적은 다음, \
주방장이 알아볼 수 있는 표준 약어(예: `K-JJG-1`)로 바꿔서 주방 창구에 끼워 넣는다. \
주방은 매니저가 끼워둔 약어만 보고 일한다. 손님과 주방은 절대 직접 이야기하지 않는다.

이 "손님이 외친 말 → 매니저가 옮겨 적은 양식 → 주방이 받는 약어"의 흐름이, \
**함수 호출 → 시스템 콜(system call) → CPU 명령어**의 흐름이다.

그리고 주방장이 받는 약어는 사람의 언어가 아니라 "1번 화구 켜기 / 5번 그릇 꺼내기" 같은 **단순한 동작 단위**다. \
사람이 보기 편하라고 약어로 표시할 뿐, 실제로 주방 기계에 들어가는 신호는 더 짧은 **숫자 코드**다. \
이게 컴퓨터에서 **어셈블리(assembly, 사람이 읽을 수 있는 약어)** 와 **기계어(machine code, 0과 1로만 된 신호)** 의 관계다. 둘은 같은 동작을 가리키는 두 표기일 뿐이다. 3장에서 본다.

#### 매니저(OS)의 네 가지 직무

매니저는 한 명이지만 머릿속에서 네 가지 역할을 동시에 굴린다.

* **인사관리 = 프로세스(Process) 관리**: 어느 손님을 먼저 받고, 어느 주문서를 어느 주방장에게 줄지 정한다. 누가 새로 들어왔고 누가 나갔는지 장부에 적는다.
* **식자재 관리 = 메모리 관리**: 냉장고 어느 칸에 어떤 재료가 있는지, 어느 칸은 비었는지, 누구에게 어느 칸을 빌려줬는지 추적한다. 손님끼리 서로의 재료를 못 만지게 막는 것도 매니저의 일이다.
* **출입 관리 = 파일 시스템**: 창고(디스크)에 들어가는 길은 매니저만 안다. 손님이 "재료 좀 더 꺼내달라"고 하면 매니저가 대신 다녀온다.
* **손님 응대 = 입출력(I/O) 관리**: 종이 영수증 출력, 손님 부르는 벨, 카운터에서 들어오는 카드 결제 신호. 매니저가 모든 입출구를 통제한다.

"OS는 막연한 한 덩어리가 아니라 네 가지 직무를 동시에 굴리는 조직"이다

#### 매니저 한 명이 어떻게 여러 손님을 동시에 받나

음식점에 손님이 100명 들어와도 매니저가 한 명이라면, 매니저는 어떻게 동시에 다 응대할까. \
진짜로 동시에 하는 건 아니고, 매니저는 **한 손님과 아주 짧은 시간(예: 1초)만 이야기하고, 다음 손님에게 넘어갔다가, 또 다음, 또 다음으로 빠르게 자리를 옮긴다**. \
사람 눈에는 너무 빨라서 "동시에 받는 것처럼" 보일 뿐이다. \
컴퓨터에서도 똑같다. \
CPU 코어 한 개는 한순간에 한 가지 일밖에 못 하지만, OS가 매우 짧은 시간 단위(보통 수\~수십 밀리초)로 작업을 바꿔치기 해서 사용자에게 "여러 프로그램이 동시에 도는 것처럼" 보이게 만든다. \
이 바꿔치기를 **컨텍스트 스위치(context switch)**, 누구를 다음에 받을지 정하는 규칙을 **스케줄링(scheduling)** 이라 부른다.&#x20;

> 진짜 음식점에서는 손님이 주방을 들여다볼 수 있지만, 컴퓨터에서는 응용프로그램이 하드웨어를 절대 직접 만질 수 없다. \
> 또 매니저(OS)는 한 명이 아니라 **여러 부서로 나뉜 거대한 조직**에 가깝다. \
> 그리고 음식점은 손님이 다 나가면 문을 닫지만, 컴퓨터는 손님(응용프로그램)이 한 명도 없어도 매니저와 주방은 계속 돌고 있다. \
> 한 가지 더 — 음식점 매니저는 한 명이고 한 번에 한 손님이지만, 실제 컴퓨터에서는 OS가 **여러 CPU 코어와 수천 개의 작업을 동시에** 지휘한다.

***

### 2. 본 내용 설명

#### 2-1. 컴퓨터의 4층 구조

컴퓨터는 아래로 갈수록 "물리"에, 위로 갈수록 "사람"에 가깝다.

```
┌───────────────────────────────────────────┐
│  4층  응용프로그램 (Application)           │  ← 크롬, 메모장, 게임 (.exe)
├───────────────────────────────────────────┤
│  3층  운영체제 (OS, Operating System)      │  ← Windows, Linux, macOS
├───────────────────────────────────────────┤
│  2층  펌웨어 (Firmware, UEFI/BIOS)         │  ← 메인보드 칩에 박힌 작은 코드
├───────────────────────────────────────────┤
│  1층  하드웨어 (Hardware)                  │  ← CPU, RAM, SSD, 키보드, 모니터
└───────────────────────────────────────────┘
```

각 층은 바로 아래 층만 알면 되도록 설계되어 있다. \
이것을 **추상화(abstraction)** 라고 부른다. \
크롬은 SSD가 SATA 방식인지 NVMe 방식인지 몰라도 파일을 읽을 수 있다. \
그 차이는 OS가 가려준다.

* **하드웨어**: 만져지는 부품. 전기가 흐르고 부품이 발열한다. \
  대표적으로 연산을 담당하는 CPU, 작업용 메모리인 **RAM**(Random Access Memory), 영구 저장소인 SSD/HDD, 입력장치(키보드·마우스), 출력장치(모니터·스피커), 그리고 이들을 한 판 위에 묶어주는 **메인보드(Mainboard)** 가 있다. 일반적인 데스크톱·노트북에 들어가는 핵심 부품을 한 줄씩 정리하면 아래와 같다.

| 부품                            | 한 줄 역할                        |
| ----------------------------- | ----------------------------- |
| CPU(Central Processing Unit)  | 명령어를 해석하고 실행하는 두뇌. 1장.        |
| GPU(Graphics Processing Unit) | 화면 그리기·병렬 계산 담당. 게임·AI에서 핵심.  |
| NPU(Neural Processing Unit)   | AI 연산 전용 가속기. 최근 노트북에 점점 들어옴. |
| RAM                           | 작업용 메모리. 빠르지만 전원 끄면 사라짐.      |
| SSD/HDD                       | 영구 저장소. 느리지만 전원 꺼도 남음.        |
| 메인보드                          | 부품들을 꽂아 묶는 판. 전원·신호를 분배.      |

부품들이 한 판(메인보드) 위에 그냥 모여만 있는 게 아니라, 부품끼리 데이터를 주고받는 표준 **버스(bus)** 가 깔려 있다. \
**PCIe**(GPU·NVMe SSD가 꽂히는 빠른 통로), **SATA**(예전 SSD·HDD가 쓰던 좀 더 느린 통로), **USB**(외부 기기용). 각 부품은 자기에게 맞는 버스 종류로 메인보드에 연결된다.

* **펌웨어**: \
  하드웨어 칩 안에 박혀서 출고된 작은 소프트웨어. 전원을 켤 때 가장 먼저 실행되고, 하드웨어를 점검한 뒤 OS를 깨운다. \
  PC에서는 **UEFI**(Unified Extensible Firmware Interface)가 대표적이다. \
  옛날에는 **BIOS**(Basic Input/Output System)가 같은 역할을 했는데, 1980년대에 만들어진 16비트 옛 설계라 큰 디스크와 빠른 부팅을 다루기 어려워 2010년대부터 UEFI로 대체되었다. \
  지금 새로 사는 PC는 거의 다 UEFI가 표준이고, BIOS라는 단어는 이름이 익숙해서 관습적으로 남아 있을 뿐이다. \
  CPU 안에도 **마이크로코드(microcode)** 라는 더 작은 펌웨어가 들어 있어(CPU가 어셈블리 명령어 한 줄을 받았을 때 그걸 내부에서 어떻게 처리할지 적어둔 더 안쪽의 설명서다) 같은 CPU라도 출고 후 일부 명령어 동작을 갱신할 수 있다. \
  펌웨어는 옛날엔 정말로 한 번 구운 뒤 못 바꾸는 **ROM**(Read-Only Memory)에 들어 있었지만, 요즘 UEFI는 **SPI 플래시 메모리**라는 작은 칩에 들어 있어 **펌웨어 업데이트**가 가능하다. \
  메인보드 제조사 사이트에서 "BIOS 업데이트"라고 부르며 내려받는 게 사실은 UEFI 펌웨어 새 버전을 그 SPI 플래시에 다시 쓰는 작업이다. \
  그리고 BIOS든 UEFI든 부팅 첫 단계에서 RAM·CPU·키보드 같은 기본 부품이 살아 있는지 확인하는 **POST**(Power-On Self-Test, 전원 인가 직후 자가 점검)를 똑같이 한다. (부팅 빕(beep) 소리가 그 시절 POST의 결과 알림이었다)
* **운영체제(OS, Operating System)**: \
  응용프로그램이 하드웨어를 안전하고 공정하게 나눠 쓸 수 있게 해주는 거대한 소프트웨어. \
  한 덩어리처럼 보이지만 안쪽을 들여다보면 크게 세 부분으로 나뉜다. \
  ① **커널(kernel)** — 진짜 권한을 가지고 하드웨어와 메모리·프로세스를 직접 다루는 심장. CPU가 제공하는 **가장 높은 권한 모드**(흔히 **커널 모드**라 부른다)로 동작한다. \
  ② **시스템 라이브러리** — 응용프로그램과 커널 사이를 잇는 표준 도구 모음(`kernel32.dll`, `user32.dll` 등). \
  ③ **셸(shell)과 사용자 인터페이스** — 사용자가 직접 보는 화면(파일 탐색기, 명령 프롬프트). 셸은 일반 응용프로그램과 같은 **가장 낮은 권한 모드**(**사용자 모드**)로 돈다. 즉 같은 OS 안에서도 영역마다 다른 권한 수준에서 돈다. (참고로 x86 CPU는 권한 레벨을 0\~3으로 매기고 커널 모드가 0, 사용자 모드가 3이라 "ring 0", "ring 3"이라는 별명으로도 부른다.) Windows, Linux, macOS가 대표.
* **응용프로그램**: \
  우리가 일상에서 "프로그램"이라 부르는 것. \
  워드, 크롬, 게임. 다만 이 응용프로그램은 **그 위에서 도는 OS가 정해준 약속을 따라야** 동작한다. \
  같은 `notepad.exe` 파일을 macOS에서 더블클릭하면 "이걸 어떻게 실행해야 하는지 모르겠다"는 오류만 뜨고 끝난다. \
  파일 내부 구조와 시스템 콜 약속이 OS마다 다르기 때문이다. \
  구체적으로, 실행 파일은 OS별로 정해진 **포맷(format)** 이 있다 — Windows는 **PE**(Portable Executable), Linux는 **ELF**(Executable and Linkable Format), macOS는 **Mach-O**. \
  같은 C 코드라도 어떤 OS용으로 컴파일하느냐에 따라 결과 파일이 PE냐 ELF냐 Mach-O냐로 갈린다. \
  그래서 Linux용으로 빌드한 `.bin`이 Windows에서 안 돌고, Windows용 `.exe`가 macOS에서 안 도는 것이다.

**커널이 안에서 하는 일 (개념)**

커널이라는 단어가 갑자기 큰 짐을 지는데, 안에서 실제로 굴리는 직무는 크게 네 가지다. 비유에서 본 매니저의 네 가지 직무와 거의 일대일로 대응된다.

1. **프로세스 관리** — 어느 프로그램을 언제 CPU에 올릴지 결정한다.
2. **메모리 관리** — RAM을 어느 프로그램에게 얼마나 빌려줄지 정한다.
3. **파일 시스템** — 디스크 위의 파일들을 이름·경로로 관리한다.
4. **장치 관리** — 키보드·모니터·네트워크 카드 같은 부품과 드라이버를 통해 대화한다.

#### 층끼리 어떻게 이야기하나

각 층이 바로 아래 층과 대화하는 방법에는 정해진 이름이 있다.

* **응용프로그램 ↔ OS**: \
  응용프로그램은 OS에게 직접 부탁할 때 **시스템 콜(system call)** 이라는 약속된 창구를 쓴다. \
  "이 파일 좀 열어줘", "이 글자 좀 화면에 그려줘" 같은 부탁이 전부 시스템 콜로 들어간다. \
  시스템 콜이 일어나는 순간 CPU는 "응용프로그램이 함부로 못 만지게 막혀 있는 상태"에서 "OS가 모든 것을 할 수 있는 상태"로 **권한 모드를 바꾼다**. \
  이 모드 전환을 **사용자 모드(user mode) ↔ 커널 모드(kernel mode) 전환**이라 부른다.
* **OS ↔ 하드웨어**: \
  OS가 각 부품(프린터·그래픽카드·마우스 등)에게 말을 걸 때는 부품마다 따로 마련된 통역기인 **드라이버(driver)** 를 거친다. \
  드라이버는 "이 부품 전용 사용 설명서".
* **펌웨어 → OS**: \
  전원을 켜면 \
  ① 메인보드의 UEFI가 깨어나 하드웨어 점검(POST, Power-On Self-Test)\
  ② 부팅 드라이브에서 **부트로더(bootloader)** 를 불러옴\
  ③ 부트로더가 OS 커널을 메모리에 올림\
  ④ 커널이 드라이버·서비스를 띄움\
  ⑤ 로그인 화면이 뜬다. 이 다섯 단계가 매번 전원 버튼을 누를 때마다 일어난다.

각 단계를 한 단계만 더 안쪽에서 보면 이렇다. (대략적 흐름)

1. **전원 인가**\
   파워 서플라이가 메인보드에 +12V·+5V·+3.3V 같은 여러 전압을 동시에 공급하고, CPU 옆 보조 전원 단자(8핀)에도 따로 전기가 들어간다. 이 모든 전원이 안정되었다는 신호(**Power Good**)가 들어와야 메인보드가 CPU의 **리셋(reset)** 핀을 풀고, 그제야 CPU가 첫 번째 명령을 가져오기 시작한다. 클럭(박자) 신호 역시 이 단계에서 안정된다.
2. **POST**\
   UEFI 코드가 가장 먼저 한다. RAM이 몇 GB 꽂혀 있는지, CPU 모델은 무엇인지, 키보드·USB 포트·디스크가 응답하는지를 빠르게 점검한다. 옛날 PC가 부팅 직후 "빕(beep)" 소리를 한 번 짧게 내는 게 이 POST가 정상 통과했음을 알리는 신호였다. POST가 실패하면 OS는 시작조차 못 한다.
3. **부트로더 적재**

   UEFI가 **EFI 시스템 파티션**(보통 디스크 맨 앞쪽에 자리 잡은 작은 FAT 파티션. 줄여서 **ESP**라고도 한다)에서 부팅 프로그램을 찾아 메모리에 올린다. Windows에서 이 부트로더의 이름이 **Windows Boot Manager**(`bootmgfw.efi` — Boot Manager의 UEFI 펌웨어용 버전이라는 뜻)이고, 이게 다시 `winload.efi`(Windows Loader)를 불러 실제 커널 적재를 준비한다. 즉 "디스크의 어디서부터 OS를 읽어올지" 결정하는 게 이 단계의 핵심이다. 파일 이름의 `.efi` 확장자는 UEFI 환경에서 실행되는 부팅 전용 실행 파일이라는 표시다. (참고로 "부트로더 자체는 그럼 어디서 실행되는가" 하는 의문이 자연스럽게 생긴다. 답은 — UEFI 펌웨어가 POST 단계에서 이미 RAM 컨트롤러를 초기화해 RAM 일부 영역을 쓸 수 있게 만든다. 그래서 UEFI가 부트로더를 디스크에서 읽어와 그 초기화된 RAM 영역에 올린 뒤 실행한다. 부트로더는 "OS 커널을 적재하기 전 단계의 임시 RAM"에서 도는 셈이다.)
4. **커널 로드**

   부트로더가 Windows 커널 본체(`ntoskrnl.exe`, "NT OS Kernel"의 줄임말)와 **하드웨어 추상화 계층**(HAL, Hardware Abstraction Layer — 커널과 메인보드별 차이 사이에 끼어 "어느 메인보드든 똑같이 보이게" 가려주는 얇은 층), 그리고 부팅에 꼭 필요한 기본 드라이버들을 RAM에 올린다. 이 시점에서 CPU는 펌웨어가 아니라 OS 커널의 코드를 처음으로 실행하기 시작한다. 화면에 회전하는 점이 등장하는 시점이 대략 여기다.
5. **사용자 모드 진입**

   커널이 시스템 서비스를 줄줄이 띄운 뒤, 첫 사용자 모드 프로세스를 차례로 띄운다. 이름이 줄임말이라 낯설지만 각각 한 줄짜리 역할이 있다.

   * `smss.exe`(Session Manager Subsystem) — "세션 관리자". 사용자별 작업 공간을 준비하는 가장 첫 사용자 모드 프로세스.
   * `wininit.exe`(Windows Initialization) — 시스템 쪽 초기화 담당. 백그라운드 서비스들을 띄운다.
   * `winlogon.exe`(Windows Logon) — 로그인 화면을 띄우고 비밀번호를 받아 사용자 인증을 처리한다.
   * 그리고 사용자가 로그인하면 `explorer.exe`(파일 탐색기 = 셸)가 떠서 우리가 보는 바탕화면을 그린다.

   사용자가 보는 모든 응용프로그램은 이 시점 이후에야 비로소 실행될 수 있다. 8장·11장에서 이 프로세스 사슬을 다시 만난다.

#### 2-2. 비트와 바이트 — 컴퓨터의 가장 작은 단어

* **비트(bit)**: 0 또는 1, 단 두 가지 상태만 가질 수 있는 정보의 최소 단위.
* **바이트(byte)**: 8개의 비트를 묶은 것. 한 바이트는 0\~255까지의 숫자 256가지 중 하나를 표현할 수 있다($2^8 = 256$).
* 그 위로는 **킬로바이트(KB), 메가바이트(MB), 기가바이트(GB), 테라바이트(TB)**.

비트가 n개 묶이면 표현 가능한 경우의 수는 $2^n$ 가지로 폭발적으로 늘어난다. \
(2비트면 4가지(`00 01 10 11`), 4비트면 16가지, 8비트면 256가지, 16비트면 65,536가지)

| 단위          | 크기         | 어느 정도?                    |
| ----------- | ---------- | ------------------------- |
| 1 B(바이트)    | 8비트        | 영어 글자 한 자                 |
| 1 KB        | 약 1,000 B  | A4 한 페이지 텍스트              |
| 1 MB        | 약 1,000 KB | 휴대폰 사진 한 장 / 짧은 음성 메모     |
| 1 GB        | 약 1,000 MB | 표준 화질 영화 한 편 / MP3 약 250곡 |
| 1 TB        | 약 1,000 GB | 영화 약 250편 / 일반 노트북 SSD 전체 |
| 1 PB(페타바이트) | 약 1,000 TB | 대형 데이터센터 한 랙(rack) 분량     |
| 1 EB(엑사바이트) | 약 1,000 PB | 전 세계 인터넷 트래픽 며칠치          |

페타·엑사는 일반 사용자가 만질 일은 거의 없다.

엄밀히는 컴퓨터 내부에서 1 KB = 1,024 B로 세지만(2의 제곱이라서 편하다), 제조사·OS가 단위를 다르게 표시해서 "내 1TB 디스크가 931GB로 잡힌다" 같은 차이가 생긴다.

이 차이가 실제로 어떻게 만져지는지 한 번만 짚어둔다. SSD 제조사는 보통 "1TB = 1,000,000,000,000 B" (10진법)로 광고한다. 그런데 Windows는 1GB = 1,073,741,824 B (2진법, 2^30)으로 센다. 그러니까 같은 1TB SSD를 OS가 다시 세면 1,000,000,000,000 ÷ 1,073,741,824 ≈ **931GB**가 된다. 디스크가 고장난 게 아니라 단위 환산의 차이일 뿐이다.

왜 8비트인가? "영어 알파벳 한 글자를 표현하는 데 한 단위가 필요하다"는 실용적 이유로 IBM이 1960년대에 굳혔다. 그 결과 한 바이트는 한 글자(ASCII 기준)에 해당한다.

**한 바이트가 표현하는 것들**

같은 1바이트라도 우리가 "어떻게 해석하기로 약속했느냐"에 따라 의미가 완전히 달라진다. 비트 패턴 자체는 그냥 8개의 0/1일 뿐이고, 의미는 약속이 결정한다.

* **부호 없는 정수(unsigned integer)**: \
  0부터 255까지 256가지의 양의 정수. 가장 단순한 해석이다.
* **부호 있는 정수(signed integer)**: \
  -128부터 127까지. \
  음수를 표현하기 위해 **2의 보수(two's complement)** 라는 약속을 쓴다. (가장 윗 비트를 부호로 쓰되, 음수는 "비트를 다 뒤집고 1을 더한 값"으로 정의한다.) \
  예를 들어 8비트로 `+1`은 `0000 0001`이고, 이걸 `-1`로 만들려면 \
  ① 모두 뒤집어 `1111 1110`\
  ② 1을 더해 `1111 1111`이 된다. \
  그래서 -1은 8비트에서 `1111 1111`로 저장된다. \
  마찬가지로 -2는 `1111 1110`, -128은 `1000 0000`이다. \
  더하기 회로 한 가지만으로 양수·음수를 모두 다룰 수 있어 CPU 설계가 단순해진다. \
  (`1111 1111`이라는 같은 비트 패턴이 부호 없는 정수로는 255, 부호 있는 정수로는 -1이다. 그럼 CPU는 어떻게 구별하나? 답은 **구별하지 않는다**. \
  비트는 그저 8개의 0/1일 뿐이다. \
  어셈블리 명령어가 "부호 있는 비교(`jl`, `jg`)"를 쓰느냐 "부호 없는 비교(`jb`, `ja`)"를 쓰느냐, 그리고 C 코드가 변수 타입을 `signed char`로 선언했냐 `unsigned char`로 선언했냐로 의미가 결정된다. \
  같은 비트 패턴 위에 어떤 해석기를 얹느냐의 문제다. 이 점은 3장에서 다시 본다.)
* **부동소수점(floating-point)**: \
  1바이트로는 부족해서 보통 4바이트(`float`) 또는 8바이트(`double`)를 쓴다. \
  표준 이름은 **IEEE 754**. 한 줄만 풀이하면, 한 숫자를 **부호 비트(±) + 지수부 + 가수부** 세 토막으로 쪼개서 저장한다. \
  32비트 `float`는 1+8+23비트, 64비트 `double`은 1+11+52비트로 나뉜다. \
  이 표현 덕분에 매우 큰 수(예: $10^{38}$)와 매우 작은 수(예: $10^{-38}$)를 한 형식으로 다 다룬다. \
  다만 그 대가로 0.1 같은 십진수 소수가 2진법으로는 무한 반복이라 약간 어긋난 값으로 저장된다.
* **문자(character)**: \
  어떤 인코딩을 약속했느냐에 따라 한 바이트가 한 글자일 수도, 한 글자의 일부일 수도 있다.

**문자 인코딩 — 글자와 바이트의 변환 약속**

"안녕"이 어떻게 0과 1로 바뀌느냐는 한 가지 답이 없다. **인코딩(encoding)** 이라는 약속을 무엇으로 골랐느냐에 따라 다르다.

* **ASCII**(American Standard Code for Information Interchange): 1963년에 정해진 7비트 인코딩. 영문자·숫자·기호 128가지만 표현한다. 한 글자가 정확히 한 바이트(사실은 7비트지만 한 바이트 칸에 담는다)다. 한글·일본어·이모지는 표현 불가.
* **UTF-8**(Unicode Transformation Format, 8-bit): 지금 인터넷·OS 표준. 한 글자가 1\~4바이트로 **가변 길이**다. 영문 한 글자는 1바이트, 라틴 확장(é, ñ)은 2바이트, 한글 한 글자는 3바이트, 이모지는 보통 4바이트다.
* **UTF-16**: Windows 내부가 즐겨 쓰는 인코딩. 대부분 글자가 2바이트.

UTF-8이 어떻게 바이트 수를 자동으로 늘렸다 줄였다 하는가? \
**유니코드 코드포인트**(글자에 매겨진 번호, `U+` 다음에 16진수)의 범위에 따라 바이트 수가 정해진다.

| 코드포인트 범위            | 바이트 수 | 어떤 글자?                    |
| ------------------- | ----- | ------------------------- |
| U+0000 \~ U+007F    | 1바이트  | 영문, 숫자, 기본 기호 (ASCII와 동일) |
| U+0080 \~ U+07FF    | 2바이트  | 라틴 확장(é, ñ), 그리스어, 키릴     |
| U+0800 \~ U+FFFF    | 3바이트  | 한글, 한자, 일본어 가나            |
| U+10000 \~ U+10FFFF | 4바이트  | 이모지, 옛 한글, 희귀 문자          |

여기서 1바이트 영역이 **ASCII와 똑같이 생긴 비트 패턴**이다. \
그래서 옛날에 ASCII로 만들어진 영어 텍스트 파일은 한 비트도 안 바꾸고 그대로 "올바른 UTF-8 파일"로 읽힌다. \
UTF-8이 인터넷을 평정한 이유 중 하나가 이 **하위 호환성**이다.

여기서 자주 빠지는 함정은 **"1바이트 = 1글자"가 더 이상 아니다**는 점. \
`"hi"`는 UTF-8로 2바이트지만 `"안녕"`은 6바이트다. \
파일 크기를 보고 "글자 수"를 짐작하면 한국어·이모지가 섞이는 순간 어긋난다.

> **주의 — `len("안녕")`이 2로 나오는 이유** 파이썬 3에서 `len("안녕")`은 2를 돌려준다. 이건 바이트 수가 아니라 **글자 수(코드포인트 수)** 다. 파이썬 3의 문자열은 내부에서 유니코드 코드포인트 단위로 저장·취급되기 때문이다. 실제 바이트 수가 보고 싶으면 `len("안녕".encode("utf-8"))`을 찍어야 하고, 그제야 6이 나온다. 같은 문자열을 글자 수로 셀지, 바이트 수로 셀지를 언어가 어떻게 약속해뒀느냐의 차이일 뿐이다. C의 `strlen()`처럼 바이트 수를 돌려주는 함수도 있고, 자바스크립트의 `"안녕".length`처럼 또 다른 단위(UTF-16 코드 단위)를 쓰는 언어도 있다.

#### 2-3. 디지털 신호 — "0과 1"의 실체

컴퓨터 안에서 "0"과 "1"은 추상적인 숫자가 아니라 **전압의 높낮이**다.

* 약 0V 근처 = `0`
* 약 1\~3V 근처 = `1`

전기는 매우 빠르게 켜졌다 꺼졌다 할 수 있어서, 초당 수십억 번도 신호를 바꿀 수 있다. \
이 "켰다 껐다"의 패턴이 곧 명령어와 데이터다. \
결국 우리 컴퓨터 안에서 일어나는 모든 일은 **수많은 작은 스위치가 매우 빠르게 켜졌다 꺼졌다 하는 일**이다.

아날로그 신호(전압이 연속적으로 변하는 신호)와 달리, 디지털 신호는 "이 정도면 0, 이 정도면 1"로 잘라 해석하기 때문에 노이즈에 강하고 복제해도 흐려지지 않는다.

디지털 회로는 **역치(threshold) 비교 회로**를 곳곳에 깔아둔다. \
"입력 전압이 0.8V 아래면 무조건 `0`, 1.5V 위면 무조건 `1`"이라는 식으로 잘라버린다. \
그래서 신호 선을 따라 가다가 잡음이 0.3V쯤 덧붙어도 결과는 여전히 `0`이나 `1` 그대로 살아남는다. \
아날로그 신호는 0.3V만큼 그대로 왜곡되어버리는 것과 대조적이다. \
음악 CD를 100번 복사해도 원본과 똑같이 들리는 이유가 이 "역치 복구" 덕분이다.

**차동 시그널링 — 빠른 통신선이 두 가닥인 이유**

USB, HDMI, PCIe 같은 빠른 신호선의 단면을 보면 신호 한 개를 보내는 데 **두 가닥의 전선**을 쓴다. \
한쪽엔 원래 신호, 다른 쪽엔 그 신호를 정확히 뒤집은 신호(±)를 동시에 흘리고, 받는 쪽은 **두 선의 전압 차이**로 0/1을 판단한다. \
이걸 **차동 시그널링(differential signaling)** 이라 부른다. \
이렇게 하면 외부 잡음이 두 선에 똑같이 들러붙더라도 "차이"는 그대로 남아서 신호가 깨지지 않는다. \
USB·HDMI·이더넷·PCIe가 다 차동 쌍(differential pair)을 쓰는 이유다. \
한 가닥짜리 단순 신호선은 50cm만 길어져도 잡음에 흔들리지만, 차동 쌍이면 수 미터를 가도 멀쩡하다.

CPU와 RAM 사이는, **DDR4까지의 RAM(DIMM)은 한 가닥짜리 단일 신호선(single-ended)** 을 쓴다. \
거리가 메인보드 위 몇 cm로 매우 짧고, 잘 차폐되어 있어 단일 신호로도 충분하기 때문이다. \
다만 클럭 신호처럼 특히 정확해야 하는 일부 신호는 옛날부터 차동 쌍을 썼다. \
그러다 속도가 더 빨라진 **DDR5와 LPDDR5**부터는 데이터 신호도 차동 비슷한 기법(DFE, 디스큐, 패턴 부호화)을 본격적으로 끌어들였고, GPU에 붙는 **GDDR/HBM**처럼 더 빠른 메모리는 거의 다 차동 쌍 구조다. \
즉 "가까우면 단일, 빨라지거나 멀어지면 차동".

전압만 0과 1을 표현하는 방법인 것도 아니다.

* SSD 안의 **플래시 셀**: 전자를 가뒀나(0) / 안 가뒀나(1)로 정보 저장.
* HDD/자기 테이프: 자기장 방향(N→S 인가 / S→N 인가)으로 0/1.
* 광디스크(CD/DVD): 표면의 작은 홈(pit)이 있느냐 / 없느냐를 레이저로 읽음.
* 광섬유 통신: 빛의 켜짐/꺼짐.

매체는 달라도 모두 "물리적으로 안정적으로 두 상태로 갈리는 무언가"를 골라 0과 1에 대응시킨다는 발상은 같다.

**클럭 — 디지털 회로의 박자**

0과 1이 시간 축 위에서 켜졌다 꺼졌다 하려면 "지금 이 신호를 읽어라"는 박자가 필요하다. \
그 박자를 만드는 것이 **클럭(clock)** 신호다. \
메인보드와 CPU 안에는 매우 정밀하게 같은 간격으로 진동하는 **수정 진동자(crystal oscillator)** 가 있어, 그 진동을 박자삼아 모든 부품이 한 박씩 일을 진행한다. \
CPU가 "3GHz"라고 하면 초당 30억 번 박자를 친다는 뜻이다.

메인보드의 수정 진동자는 보통 100MHz 수준의 비교적 낮은 박자만 만든다. \
CPU는 이 박자를 받아 **PLL**(Phase-Locked Loop)이라는 회로로 내부에서 수십 배로 곱해 GHz 단위까지 끌어올린다. \
PLL을 한 줄로 풀면 "들어온 박자에 자기 박자를 잠가서(lock) 정확히 같은 리듬으로 더 빠르게 치는 회로"다. \
그래서 같은 100MHz 외부 클럭으로 어떤 CPU는 3GHz, 어떤 CPU는 5GHz로 돌 수 있다. \
이 곱하는 배수를 **배수기(multiplier)** 라 부르고, 같은 100MHz × 30배 = 3GHz, × 50배 = 5GHz가 된다. \
배수는 CPU 모델마다 공장에서 정해져 있고, 일부 고급 모델(인텔의 K 시리즈, AMD의 X 시리즈)은 이 배수를 사용자가 BIOS에서 끌어올릴 수 있게 잠금이 풀려 있다. \
그 행위가 곧 **오버클럭(overclocking)** 이다.

**신호 무결성 — 선이 길어지면 일어나는 일**

이상적으로는 디지털 신호가 노이즈에 무한히 강하지만, 현실에서는 **케이블이 길어지거나 주변 전자기 간섭이 강해지면** 신호가 흐물흐물해진다. \
신호의 상승·하강이 무뎌져 역치 회로가 0과 1을 헷갈리기 시작한다. \
이 한계를 **신호 무결성(signal integrity)** 문제라고 부른다. \
USB 3.0 케이블이 3m 이상 잘 안 만들어지는 것도, HDMI 케이블이 길어지면 화면이 깨지는 것도 같은 이유다. \
그래서 빠른 신호일수록 선을 짧게 두거나 중간에 신호를 다시 깨끗하게 펴주는 **리피터(repeater)** 칩이 들어간다.

**양자화 — 아날로그를 디지털로 옮길 때 일어나는 일**

마이크가 잡는 목소리, 카메라 센서가 받는 빛은 원래 **아날로그**다. \
연속적으로 변하는 전압이나 빛의 세기다. \
이것을 컴퓨터가 다루려면 "특정 시각에 측정한 값을 가장 가까운 정수(예: 0\~255 사이)에 떨어뜨려" 디지털 숫자로 바꿔야 한다. \
이 과정을 **양자화(quantization)**, 이걸 하는 부품을 **ADC**(Analog-to-Digital Converter, 아날로그→디지털 변환기)라 부른다. \
떨어뜨리는 순간 사이값은 잘려나가서 약간의 손실이 생긴다. \
음원을 8비트로 녹음하면 거칠게, 24비트로 녹음하면 매끈하게 들리는 차이가 양자화 정밀도의 차이다. \
반대 방향(디지털→아날로그)을 하는 부품은 **DAC**다. 스피커로 소리를 내보낼 때 쓴다.

양자화에는 "얼마나 자주 측정하느냐"도 중요한데, 여기엔 수학적 기준이 있다. \
**샘플링 정리(Sampling Theorem, 나이퀴스트 정리)** — 원래 신호에 들어 있는 가장 높은 주파수의 **두 배 이상**으로 측정해야 손실 없이 복원할 수 있다. \
사람이 듣는 소리의 한계는 약 20kHz이므로, 그 두 배보다 살짝 여유를 둔 **44.1kHz**가 음악 CD의 표준 샘플링 주파수가 되었다. \
즉 CD에 담긴 노래는 초당 44,100번 음압을 측정해 16비트 정수로 적어둔 셈.

***

### 3. 실습 — 내 컴퓨터에서 OS와 프로그램을 눈으로 보기

#### 준비물

* Windows 11이 설치된 PC.

#### 실습 A. 작업 관리자(Task Manager)로 "지금 돌고 있는 프로그램들" 보기

1. `Ctrl` + `Shift` + `Esc` 작업 관리자를 연다.
2. **"프로세스(Processes)"** 탭 → 왜: 지금 이 순간 내 컴퓨터에서 실행 중인 모든 프로그램의 목록을 본다.
3. 목록을 위에서 아래로 한 번 훑어본다. 익숙한 이름(크롬, Edge 등)과 낯선 이름(Service Host, Windows Explorer 등)이 섞여 있다.
4. **"CPU"** 와 **"메모리(Memory)"**  → 각 프로그램이 지금 얼마나 CPU와 메모리를 쓰는지 보인다.&#x20;
5. **"PID"** 열을 켠다. → 각 프로세스에는 OS가 부여한 정수 번호 **PID**(Process ID)가 있다. 이름이 같은 프로세스(예: `chrome.exe`가 십수 개)를 구별할 때 PID가 유일한 신분증 역할을 한다.
6. **"세부 정보(Details)"** 탭(왼쪽 메뉴)을 한 번 눌러본다. → 여기엔 사람이 알아보기 쉽게 묶인 이름 대신 진짜 실행 파일 이름(`notepad.exe`, `explorer.exe` …)이 그대로 나온다.

**열의 의미 한 줄씩**

* **이름**: 프로세스가 자기를 소개할 때 쓰는 표시 이름. 실제 실행 파일명과 다를 수도 있다.
* **PID**: OS가 부여한 고유 번호. 같은 프로세스가 종료되고 나중에 같은 PID가 다른 프로세스에게 재사용될 수 있다.
* **CPU(%)**: 모든 코어를 합쳐 지금 이 프로세스가 차지하는 CPU 비율. 4코어 기준 한 코어를 풀로 쓰면 약 25%로 보인다.
* **메모리**: 정확히는 "작업 집합(Working Set)"이라 해서, 지금 RAM에 실제로 올라와 있는 양. 디스크로 쫓겨난 부분은 빠진다. \
  작업 관리자에서 열을 추가하면 비슷한 이름의 **"커밋 크기(Commit Size)"** 도 볼 수 있는데, 이건 "이 프로세스가 OS에게 빌려가도 된다고 허락받은 메모리의 총량"이다. \
  워킹 셋이 "지금 진짜로 RAM에 올라온 양"이라면, 커밋은 "쓰겠다고 예약해둔 양"으로 보통 더 크다. \
  (참고로 "8GB 중 7GB 쓰고 있다"가 떠 있다고 해서 컴퓨터가 곧 멈추는 건 아니다. RAM이 더 필요해지면 OS가 자주 안 쓰는 페이지를 디스크의 **페이지 파일**(`C:\pagefile.sys`)에 적어두고 그 공간을 비운다. 이 동작을 **페이징/스왑(paging)** 이라 부른다. 다만 페이징이 빈번해지면 SSD를 끊임없이 읽고 쓰느라 시스템이 눈에 띄게 느려지는데, 이걸 **스래싱(thrashing)** 이라 부른다.)

**"세부 정보" 탭에서 보이는 것?**

같은 이름의 프로세스가 여러 개 떠 있을 수 있다. 가장 흔한 예가 `chrome.exe`다. 크롬은 탭(tab) 하나하나, 확장 프로그램 하나하나를 **서로 다른 프로세스로 분리**해서 띄운다. 한 탭이 충돌해도 다른 탭이 멀쩡한 이유, 그리고 작업 관리자에 `chrome.exe`가 십수 개 보이는 이유다. 같은 이름이지만 PID가 전부 달라서 OS가 구별한다.

프로세스에는 **부모-자식 관계**가 있다. \
어떤 프로세스가 다른 프로세스를 만들면, 만든 쪽이 부모, 만들어진 쪽이 자식이다. \
예를 들어 파일 탐색기(`explorer.exe`)에서 메모장을 더블클릭하면 메모장은 탐색기의 자식 프로세스로 태어난다. \
이 부모-자식 사슬을 모은 그림을 **프로세스 트리(process tree)** 라 부른다. \
작업 관리자에서는 잘 안 보이지만 Process Explorer라는 도구로 트리 모양으로 시원하게 볼 수 있다.

"세부 정보" 탭에서 임의 프로세스를 우클릭하면 **"우선순위 설정(Set priority)"** 이라는 메뉴가 보인다. 여기서 "실시간 / 높음 / 보통 위 / 보통 / 보통 아래 / 낮음"을 고를 수 있는데, 이 숫자가 다음에 OS가 누구에게 CPU를 더 자주 양보할지 정할 때 쓰는 가중치다.

#### 실습 B. `C:\Windows\System32` 들여다보기

1. `Win` 키 + `E` 를 눌러 파일 탐색기를 연다. → 파일 탐색기(`explorer.exe`)도 사실은 하나의 프로그램이다.&#x20;
2. 주소창 `C:\Windows\System32` 라고 입력 → 이 폴더는 Windows의 핵심 부품들이 모여 있는 곳이다. "OS의 본체"가 어디에 실재하는지 본다.
3. `.exe`로 끝나는 파일(`notepad.exe`, `cmd.exe` 등)과 `.dll`로 끝나는 파일이 잔뜩 보인다. →  `.exe`는 실행 파일, `.dll`은 여러 프로그램이 공용으로 쓰는 부품 라이브러리다. 이 자료의 주인공인 `.exe`가 어디에 있는지 본다.
4. `notepad.exe`를 한 번 마우스 오른쪽 클릭 → **속성(Properties)** → **자세히(Details)** 탭을 본다. → 왜: "파일 설명", "회사", "파일 버전" 같은 정보가 보인다. 모든 `.exe`는 자기 자신을 소개하는 작은 명함을 안에 들고 다닌다. 이 명함은 9장에서 볼 **PE 헤더** 안에 적혀 있다.

**왜 하필 `System32` 인가?**

`C:\Windows\System32`는 그냥 시스템 파일을 모아둔 폴더가 아니라, Windows가 부팅하면서 자동으로 **PATH 환경변수**에 등록해주는 "검색 경로"이기도 하다. \
PATH는 OS가 명령어를 찾을 때 들여다보는 폴더 목록인데, 그래서 `cmd`에서 `notepad`만 입력해도 메모장이 뜬다(전체 경로 `C:\Windows\System32\notepad.exe`를 안 적어도 OS가 자동으로 PATH의 폴더들을 뒤져 찾아준다).&#x20;

이 폴더 안의 핵심 `.dll`:

* `ntdll.dll` — 사용자 모드에서 커널로 들어가는 **마지막 관문**. 모든 Windows 프로세스에 무조건 로드된다.
* `kernel32.dll` / `kernelbase.dll` — `CreateFile`, `ReadFile`, `WriteFile` 같은 기본 API를 응용프로그램에게 노출하는 라이브러리.
* `user32.dll` — 창·메뉴·메시지 박스 같은 GUI 부품을 다루는 라이브러리.
* `gdi32.dll` — 화면에 글자·선·도형을 그리는 라이브러리.

그리고 응용프로그램이 어떤 DLL을 부르려 할 때 OS는 아무 폴더나 뒤지지 않고 **정해진 순서**로 찾아본다. \
① OS가 미리 한 번만 올려두고 모두에게 공유하는 핵심 DLL 목록(**KnownDLLs**)을 가장 먼저 본다\
② 그 다음 응용프로그램 자기 폴더\
③ 그 다음 `System32` 같은 시스템 폴더\
④ 마지막으로 PATH의 폴더들. 이 순서가 어긋나면 엉뚱한 DLL이 끼어들어 동작이 망가지거나 보안 사고가 난다. \
\
"DLL이 그냥 발견되는 게 아니라 우선순위가 있다"

KnownDLLs가 "미리 올려둔다"는 말 — 부팅 직후 세션 관리자(`smss.exe`)가 레지스트리(`HKLM\System\CurrentControlSet\Control\Session Manager\KnownDLLs`)에 적힌 DLL 이름 목록을 읽어, 그 DLL들을 한 번씩 메모리에 올려두고 **이름 붙은 공유 메모리 객체**로 등록해둔다. \
이후 어떤 프로세스가 그 DLL을 필요로 하면 OS는 디스크에서 다시 읽지 않고 이미 올라와 있는 그 공유 객체를 자기 주소 공간에 **매핑**만 해서 갖다 쓴다. \
그래서 "한 번만 올려두고 모두가 공유"가 가능하다.&#x20;

`System32` 폴더 안에는 DLL 외에 우리에게 익숙한 실행 파일

* `regedit.exe` — Windows의 설정 데이터베이스인 **레지스트리(registry)** 를 직접 열어보는 도구.
* `cmd.exe` — 옛날부터 있는 명령 프롬프트. 까만 화면에 명령어를 친다.
* `powershell.exe` — `cmd`의 후계자. 명령어가 더 풍부하고 객체 단위로 다룬다.
* `taskmgr.exe` — 우리가 방금 연 작업 관리자 본체.

**그런데 이름은 `System32`인데 안에 64비트 파일?**

64비트 Windows를 쓰는데 폴더 이름이 32가 붙어 있다는 점이 헷갈린다. \
옛날 32비트 Windows 시절 16비트와 구분하려고 `System32`라는 이름을 썼다. \
나중에 64비트 Windows가 나오면서 호환성을 깨지 않으려고 **이름을 그대로 두고**, 안에 64비트 파일을 넣었다. \
그리고 32비트 응용프로그램이 쓸 32비트 DLL은 따로 `C:\Windows\SysWOW64`(WOW = Windows on Windows)에 넣었다. \
결과적으로 이름이 거꾸로 보이는데(`System32` → 64비트 / `SysWOW64` → 32비트), 이미 수많은 프로그램이 `System32` 경로를 박아 두고 만들어졌기 때문에 어쩔 수 없는 선택이었다. \
(윈도우의 가장 유명한 "역사적 부채" 중 하나다.)

***

### 4. TMI

> 💡 **TMI 1. "비트(bit)"라는 단어는 누가 만들었나** 1948년 수학자 클로드 섀넌(Claude Shannon)이 정보이론 논문에서 처음 정식으로 썼다. **"binary digit"** 의 줄임말이다. 줄임 자체는 통계학자 존 튜키(John Tukey)가 제안했다고 한다. 둘이 점심 먹다가 정해진, 컴퓨터 역사상 가장 영향력 있는 약어 중 하나다. 섀넌의 그 논문 제목은 *"A Mathematical Theory of Communication"* 으로, 오늘날 통신·암호·압축의 이론적 토대가 된 글이다.

> 💡 **TMI 2. 1바이트가 왜 하필 8비트인가** 사실 옛날 컴퓨터들은 1바이트가 6비트, 7비트, 9비트인 경우도 있었다. 8비트로 고정된 결정적 계기는 1964년 IBM System/360이다. 영어 알파벳·숫자·기호를 다 표현하려면 7비트면 충분했지만, IBM이 "확장 여유 1비트 더 두자"고 정해버렸고, 이게 표준이 되었다. 그래서 우리가 지금 1바이트 = 8비트 = 256가지를 쓴다. "정확히 8비트"임을 강조하고 싶을 때 학계는 **옥텟(octet)** 이라는 단어를 쓰며, 인터넷 RFC 표준 문서들이 이 표기를 좋아한다.

> 💡 **TMI 3. "Windows"라는 이름은 어디서 왔나** 이전의 MS-DOS는 화면 전체에 한 가지 작업만 띄울 수 있었다. 마이크로소프트는 1985년에 화면을 여러 직사각형 "창(window)"으로 나눠 여러 작업을 동시에 보여주는 새 운영체제를 내면서 그냥 이름을 **Windows**라고 붙였다. 너무 일반적인 단어라 한때 "단어 자체를 상표로 쓸 수 있느냐"로 법정 다툼이 있었지만 결국 MS가 가져갔다. 정식 출시 첫 버전은 1985년의 Windows 1.0이고, 지금 우리가 쓰는 Windows 11은 그 직계 후손이다. 한 가지 더 — 사실 "여러 창을 동시에 띄우는 화면" 발상 자체는 MS가 아니라 1973년 제록스(Xerox PARC) 연구소의 **Alto** 컴퓨터에서 시작됐다. 그 발상을 보고 베낀 첫 상용 OS가 1984년 애플의 Macintosh고, 마이크로소프트는 그 다음 해에 따라왔다. 그래서 GUI 운영체제의 가족 나무 뿌리에 늘 PARC가 있다.

> 💡 **TMI 4. "32비트 / 64비트"의 진짜 의미** 이 숫자는 "CPU가 한 번에 처리하는 데이터의 폭"과 "메모리 주소를 표현하는 비트 수"를 가리킨다. 32비트 CPU는 메모리 주소를 32비트로 표현하므로 최대 $2^{32}$ = 약 4GB 까지만 가리킬 수 있다. 64비트 CPU는 이론상 $2^{64}$ 바이트, 즉 약 1700만 TB까지 가리킬 수 있다. 그래서 큰 메모리를 쓰려면 64비트가 필수다. "두 배 빠르다"는 뜻은 아니다. 실제 현재 x86-64 CPU들은 그 어마어마한 범위를 다 쓰진 않고 48비트(256TB)만 활용한다. 메인보드에 256TB짜리 RAM을 꽂을 일도 없으니 충분한 셈이다.

> 💡 **TMI 5. 한국어 한 글자는 몇 바이트?** 영문 글자는 한 바이트지만, 한글은 표현 가능한 글자 수가 워낙 많아 그 안에 안 들어간다. 요즘 표준인 **UTF-8**(가변 길이 유니코드)에서는 한글 한 글자가 **3바이트**다. 그래서 같은 글자 수의 글을 영어와 한국어로 비교하면 한국어 텍스트 파일이 대략 3배 크다. 메모장에서 파일을 저장할 때 "인코딩"을 고를 수 있는데, 거기 보이는 UTF-8, UTF-16, ANSI가 다 글자를 비트로 바꾸는 약속의 이름이다. 이모지는 보통 한 글자가 4바이트인데, 깃발 이모지(🇰🇷처럼 두 글자 결합)나 가족 이모지(👨‍👩‍👧)는 결합 방식 때문에 8\~28바이트까지 늘어나기도 한다. "이모지 하나 = 한 글자"라는 직관이 컴퓨터 입장에서는 절대 맞지 않는 셈이다.

> 💡 **TMI 6. K(킬로)의 대소문자, 그리고 2진 단위 KiB** 단위 접두사에서 큰 단위는 보통 대문자(M=메가, G=기가, T=테라), 작은 단위는 소문자(m=밀리, μ=마이크로)다. 그런데 \*\*킬로(kilo)\*\*는 미터법 원칙대로면 소문자 `k`다 — `km`(킬로미터), `kg`(킬로그램). 그런데 컴퓨터 분야에서는 관습적으로 대문자 `K`를 자주 쓴다(KB, KHz). 표준이 흔들리는 유일한 접두사다. 한편 2진법 단위인 1024바이트를 정확히 가리키려고 IEC가 1998년에 **KiB**(키비바이트, kibibyte), **MiB**(메비바이트) 같은 새 표기를 만들었다. 안 익숙해서 일반 사용자는 잘 모르지만, 리눅스 명령어나 메모리 칩 데이터시트에서는 종종 본다. 즉 정확히 말하면 "내 RAM은 16GiB"가 맞고, 디스크 라벨의 "1TB"는 1조 바이트가 맞다.

> 💡 **TMI 7. 컴퓨터의 마법의 숫자 "4KB"** 컴퓨터 곳곳에서 4KB(4096바이트)라는 숫자가 자꾸 등장한다. Windows의 파일시스템(NTFS, FAT32)이 디스크를 잘라 관리하는 기본 단위(**클러스터**)도 보통 4KB고, OS가 RAM을 잘라 관리하는 단위(**페이지**)도 4KB다. 우연이 아니다 — 페이지와 클러스터를 같은 크기로 맞춰두면, 디스크의 한 클러스터를 RAM의 한 페이지로 통째로 옮기는 일이 군더더기 없이 떨어진다. 그래서 4KB는 OS와 디스크가 손발을 맞추기 위해 산업이 합의한 마법의 숫자다. 너무 작으면 관리 비용이 크고, 너무 크면 작은 파일을 저장할 때 공간이 낭비된다. 4KB는 그 절충점이고, 9장에서 페이지 단위로 다시 만난다.

***

### 5. Q\&A

**Q1.** OS는 프로그램인가요?&#x20;

**A.** 그렇다. OS도 누군가가 코드로 짠 **거대한 프로그램**이다. \
다만 일반 응용프로그램과 달리 "다른 프로그램들을 관리하는" 특별한 권한을 가진 프로그램이다. \
음식점 매니저도 사람이지만, 손님과는 다른 권한과 역할을 가진 사람인 것과 같다. OS의 실체 파일들은 방금 본 `C:\Windows\System32` 안에 들어 있다. \
가장 핵심 파일이 `ntoskrnl.exe`이며, 이게 우리가 부르는 "Windows 커널"의 본체다. \
규모로 비교하면 Windows 11 전체 소스 코드는 수천만 줄에 이르고, 메모장(`notepad.exe`)이 수만 줄.

**Q2.** Windows를 끄면 CPU도 꺼지나요?&#x20;

**A.** CPU는 Windows의 일부가 아니라 **하드웨어 부품**이다. \
Windows는 그 위에서 도는 소프트웨어일 뿐이다. \
"Windows를 끈다"는 것은 정확히는 OS가 CPU에게 "이제 안전한 상태이니 전원을 내려도 된다"고 알려주고, 그 신호를 받은 메인보드가 실제 전원을 차단하는 과정이다. \
그러니 CPU가 꺼지는 시점은 Windows가 꺼지는 시점보다 살짝 나중이다. \
반대로 "절전 모드"는 CPU 전원만 잠시 꺼두고 RAM은 계속 살려두는 상태라, 깨어날 때 OS를 처음부터 다시 켜지 않아도 된다.

**Q3.** 64비트 컴퓨터는 32비트보다 두 배 빠른가요?&#x20;

**A.** 아니다. 숫자만 보면 두 배지만, 그 숫자는 "속도"가 아니라 "한 번에 다루는 데이터의 폭과 가리킬 수 있는 메모리 주소의 범위"다. \
64비트 시스템은 더 큰 메모리(예: 16GB, 32GB)를 쓸 수 있고, 큰 숫자를 한 번에 더할 수 있어 일부 계산에서 빠르지만, 일반 작업이 "두 배"가 되지는 않는다. \
오히려 같은 데이터에 대해 포인터(주소)가 4바이트에서 8바이트로 늘어나기 때문에, 어떤 프로그램은 같은 일을 할 때 RAM을 조금 더 쓴다.

**Q4.** 왜 컴퓨터는 0과 1만 쓰나요?&#x20;

**A.** 전기 신호의 "있다/없다"를 가장 안정적으로 구분할 수 있기 때문이다. \
10가지 단계를 구분하려면 전압을 매우 정밀하게 측정해야 하고, 약간의 노이즈에도 값이 바뀐다. \
반면 "거의 0V"와 "거의 3V" 두 가지만 구분하면 노이즈가 좀 끼어도 헷갈리지 않는다. \
결국 0과 1은 **전기의 물리적 한계가 만든 가장 안전한 선택**이다.&#x20;

**Q5.** 프로그램과 앱과 소프트웨어는 다 같은 말인가요?&#x20;

**A.** 거의 같지만 결이 살짝 다르다. \
**소프트웨어(Software)**&#xB294; 하드웨어의 반대말로, 코드와 데이터 전체를 가리키는 가장 큰 단어다. \
**프로그램**은 그 안에서 "실행할 수 있는 한 덩어리"를 가리키고, \
**앱(Application의 줄임말)**&#xC740; 주로 "사용자가 직접 쓰는 프로그램"을 캐주얼하게 부르는 표현이다.&#x20;

**Q6.** 같은 100MHz 외부 클럭으로 CPU마다 다른 GHz가 나온다는 건 결국 곱하는 배수 차이인가요? 그리고 그게 오버클럭이랑 같은 얘기인가요? \
**A.** 정확하다. CPU마다 PLL이 곱하는 **배수(multiplier)** 가 다르고, 그 배수는 공장에서 출하될 때 정해져 있다. \
100MHz × 30 = 3GHz, 100MHz × 50 = 5GHz 같은 식이다. \
**오버클럭**은 이 배수(또는 베이스 클럭 자체)를 사용자가 BIOS/UEFI에서 정상 범위보다 더 올려 더 빠르게 돌리는 행위다. \
다만 발열·전력·안정성이 따라줘야 가능해서, 인텔의 K 시리즈, AMD의 X 시리즈처럼 배수 잠금이 풀린 모델에서 주로 한다. \
일반 모델은 배수가 잠겨 있어 오버클럭 자체가 막혀 있다.&#x20;

**Q7.** `len("안녕")`을 했더니 2가 나와요. 그럼 그건 글자 수인가요 바이트 수인가요?&#x20;

**A.** 글자 수다. \
정확히는 **유니코드 코드포인트 수**다. \
파이썬 3의 문자열은 내부에서 코드포인트 단위로 저장·취급되기 때문에 `len()`이 글자 수를 돌려준다. \
바이트 수를 보고 싶으면 `len("안녕".encode("utf-8"))`을 해야 하고, 그제야 UTF-8 기준 6이 나온다.&#x20;

**Q8.** macOS도 UEFI를 쓰나요? 아이폰 같은 스마트폰도 UEFI로 부팅하나요?&#x20;

**A.** 아니다. 인텔 시절의 맥은 UEFI 호환 펌웨어(EFI)를 썼지만, 2020년 이후의 **애플 실리콘(M1/M2/M3/...) 맥**은 애플이 자체 설계한 부팅 펌웨어(**iBoot** 계열)를 쓴다. 아이폰·아이패드도 마찬가지로 iBoot로 부팅한다. 안드로이드 스마트폰은 대체로 ARM 표준 부팅 사슬(BL1→BL2→...→리눅스 커널)을 따르며, 이 단계마다 제조사가 만든 별도 펌웨어가 들어간다. 즉 "PC = UEFI, 다른 기기 = 그 기기 전용 펌웨어"가 큰 그림이다. UEFI는 어디까지나 PC 진영의 표준이지 보편 표준은 아니다.

**Q9.** `explorer.exe`도 셸이고 `cmd.exe`나 `powershell.exe`도 셸이라는데, 셸이라는 단어가 두 번 쓰이는 건가요? \
**A.** 단어는 같고 뜻은 같다 — **사용자와 OS 사이에 끼어 명령을 전달하는 껍데기**라는 뜻. 다만 두 종류가 있다. \
① **GUI 셸**: `explorer.exe`처럼 그림·아이콘·창으로 명령을 받는다. 더블클릭, 우클릭 메뉴 같은 입력을 OS에 전달한다. \
② **CLI 셸**(Command Line Interface): `cmd.exe`, `powershell.exe`처럼 까만 화면에 타이핑한 명령어를 받는다. 둘 다 "사용자 ↔ OS 통역기"라는 본질은 똑같고, 입력 방식이 그림이냐 글자냐의 차이일 뿐이다. 그래서 같은 단어를 쓴다.

**Q11.** 작업 관리자에서 메모리가 8GB 중 7GB나 차 있어요. 곧 멈추나요? \
**A.** 곧 멈추지는 않는다. Windows는 RAM이 부족해지면 자주 안 쓰는 페이지를 SSD의 **페이지 파일**(`C:\pagefile.sys`)에 옮겨두고 그 RAM 공간을 비운다. \
이 동작이 **페이징/스왑**이고, 사용자는 보통 눈치채지 못한다. \
다만 페이징이 너무 잦아지면 SSD를 끝없이 읽고 쓰느라 시스템이 굼떠지는데, 이걸 **스래싱(thrashing)** 이라 한다.\
정말 위험한 신호는 메모리 사용량이 아니라 작업 관리자의 "성능 → 메모리"에서 **커밋된 총량이 한계에 근접**할 때다. \
그때는 OS가 메모리 부족 알림을 띄우거나 가장 무거운 프로세스를 강제 종료하기도 한다.

***
