# .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가 메모리 부족 알림을 띄우거나 가장 무거운 프로세스를 강제 종료하기도 한다.

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wonjoon.gitbook.io/joons-til/c/.exe-part1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
