# 애플리케이션 프로그래밍과  시스템 프로그래밍

## 1. **애플리케이션 vs 시스템 프로그래밍: 동물 퀴즈로 알아보기**

### 1) 웹 브라우저는 '고급 컴퓨터'다?

우리는 지난 장까지 **브라우저**를 마치 고차원의 가상 컴퓨터처럼 바라봤어요.

{% hint style="success" %}
즉, 브라우저는 HTML, CSS, JavaScript 등 '명령어'를 받아서 `DOM(Document Object Model)`을 조작하는 구조입니다.
{% endhint %}

#### ● 브라우저가 제공하는 고수준 인터페이스

* DOM API
* 이벤트 핸들러
* Ajax / Fetch 등 통신 API

이러한 고수준 API는 **운영체제와 I/O 장치의 복잡성을 감춰줍니다.**

그럼 이번 장에서는 **브라우저를 거치지 않고** 같은 프로그램을 만들면 어떻게 다를지 직접 비교해 봅시다.

### 2) 애플리케이션 vs 시스템 수준의 프로그래밍 비교

#### ● 그림 10-1의 구조 요약

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FkwXAyovHmAK8sDGMR7GC%2Fimage.png?alt=media&#x26;token=bd8f1594-7991-4df3-88e2-17cec2ac0767" alt=""><figcaption></figcaption></figure>

```
[사용자 인터랙션 프로그램 구조 비교]

프로그램 A (고수준)
 └→ 웹 브라우저 (DOM, JS로 제어)
     └→ 운영체제
         └→ I/O 장치 (키보드, 화면 등)

프로그램 B (저수준)
 └→ 직접 OS API 호출 (예: C 언어)
     └→ 운영체제
         └→ I/O 장치
```

👉 **웹 브라우저 기반**은 사용자가 다루기 쉽고 빠르게 만들 수 있습니다.\
👉 **시스템 수준 프로그래밍(C 언어 등)**&#xC740; 하드웨어와 OS 동작을 더 정확히 이해하고 제어할 수 있습니다.

### 3) 예제 프로그램: '동물 맞히기 게임'

우리가 만든 프로그램은 사용자가 생각한 동물을 컴퓨터가 질문을 통해 추측하는 간단한 지식 기반 게임입니다.

#### ● 예시 대화 흐름

```
컴퓨터: 동물을 생각해보세요.
컴퓨터: 동물이 짖습니까?
사용자: 예
컴퓨터: 개입니까?
사용자: 아니요
컴퓨터: 졌습니다. 무슨 동물입니까?
사용자: 케르베로스
컴퓨터: "머리가 3개입니까?" 라는 질문으로 구분하겠습니다.
```

#### ● 핵심 기능

1. 질문을 통해 트리 구조를 따라 내려감
2. 잎(Leaf) 노드에 도달하면 동물을 추측
3. 추측 실패 시 새로운 동물과 질문을 받아 트리 확장
4. 다음 라운드부터는 더 똑똑해짐 (학습함)

### 4) 프로그램 구조: 순서도 이해하기

#### ● 그림 10-2: 동물 퀴즈 트리 순서도 요약

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FUrT43kPdl9d9TI6F5cSA%2Fimage.png?alt=media&#x26;token=55497d4d-d1c7-4717-94b0-544ee78e9ac1" alt=""><figcaption></figcaption></figure>

그림을 보면 **동물에 대한 지식으로 이뤄진 트리를 따라 내려가되,** 질문을 던지면서 어느 경로로&#x20;내려갈지를 결정합니다.&#x20;

* 제대로 동물을 추측하면 기뻐한다.&#x20;
* 동물을 맞히지 못하면 사용자에게 정  답을 물어본 후 해당 동물을 마지막에 확인한 동물과 구분하는 데 필요한 질문을 요청해서, 그  &#x20;정보를 트리에 추가하고 처음부터 다시 시작한다.

이 프로그램은 (순서도의 왼쪽에서) **지식 트리를 따라 내려가면서 질문을 던지고 답을 얻습니다.**

> 오른쪽에서 경로의 끝에 도달하면 답을 맞혔는지 여부에 따라 잘난 체를 하거나 동물에 대한 지> 식을 지식 기반knowledge base에 추가합니다.

이 순서도를 코드로 바꾸면 아래와 같은 흐름이 됩니다:

```js
if (isLeaf(node)) {
  if (userAnswer === node.answer) {
    alert("맞췄습니다!");
  } else {
    learnNewAnimal();
  }
} else {
  if (userAnswer === "예") {
    node = node.yes;
  } else {
    node = node.no;
  }
}
```

### 5) 시스템 수준과 애플리케이션 수준의 차이

| 구분        | 애플리케이션 수준 (JS/웹)      | 시스템 수준 (C/콘솔)          |
| --------- | --------------------- | ---------------------- |
| 사용자 인터페이스 | HTML + CSS + DOM 조작   | 콘솔 출력, scanf/printf    |
| 데이터 저장    | LocalStorage, 서버      | 파일 I/O, 메모리 직접 제어      |
| 입력 처리     | `prompt`, `click` 이벤트 | `scanf`, `getchar()` 등 |
| 확장성       | 빠르고 직관적               | 복잡하지만 강력함              |

> 웹 브라우저는 이미 많은 기능이 추상화되어 있지만, **시스템 프로그래밍은 메모리, 파일, 버퍼 등 세세한 부분까지 관**리해야 합니다.

### 📌 부가설명: JSON → DB → 프론트까지 흐름도

앞서 요청하신 예시 흐름도도 아래와 같이 이어집니다.

#### ● JSON 기반 데이터 흐름

```mermaid
graph LR
  A[프론트엔드: 입력폼] --> B[JSON 생성]
  B --> C[API로 서버 전송]
  C --> D[DB에 저장 (예: MongoDB)]
  D --> E[API로 클라이언트에 재전송]
  E --> F[프론트엔드 렌더링 (React, Vue)]
```

→ 이 흐름은 현대적인 SPA 프레임워크에서 CRUD 처리의 전형적인 구조입니다.

브라우저가 '컴퓨터 같은 프로그램'이라는 비유

> 고수준 프로그래머는 DOM API만 알면 되지만,\
> 시스템 프로그래머는 '그 아래'까지 봐야 합니다.

## 2. 부가정리 :  동물 퀴즈 트리: JSON 구조 & C 구조체 변환

### 1) 동물 퀴즈 트리 구조란?

동물 맞히기 게임은 질문을 던지고 그에 따라 **예/아니오**로 가지를 뻗는 **이진 트리 구조**를 사용합니다.

예:

```
질문: 동물이 짖습니까?
 ├─ 예 → 질문: 머리가 3개입니까?
 │    ├─ 예 → 케르베로스
 │    └─ 아니요 → 개
 └─ 아니요 → 고양이
```

### 2) JSON 구조로 저장하기

```json
{
  "question": "동물이 짖습니까?",
  "yes": {
    "question": "머리가 3개입니까?",
    "yes": { "animal": "케르베로스" },
    "no": { "animal": "개" }
  },
  "no": {
    "animal": "고양이"
  }
}
```

#### 📌 JSON 저장 포인트

* 질문 노드는 `"question"` 키를 가짐
* 동물(잎 노드)은 `"animal"` 키만 있음
* `"yes"`, `"no"`로 자식 노드를 연결

### 3) C 구조체로 표현하기

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node {
    int is_question;        // 1이면 질문, 0이면 동물
    char text[128];         // 질문 or 동물 이름
    struct Node* yes;       // 예 답변
    struct Node* no;        // 아니요 답변
} Node;
```

#### 📌 사용법 예시

```c
Node* create_animal(const char* name) {
    Node* node = malloc(sizeof(Node));
    node->is_question = 0;
    strcpy(node->text, name);
    node->yes = node->no = NULL;
    return node;
}

Node* create_question(const char* question, Node* yes_node, Node* no_node) {
    Node* node = malloc(sizeof(Node));
    node->is_question = 1;
    strcpy(node->text, question);
    node->yes = yes_node;
    node->no = no_node;
    return node;
}
```

### 5) JSON ↔ 구조체 변환 개념 요약

| 항목     | JSON 저장                    | C 구조체 표현                 |
| ------ | -------------------------- | ------------------------ |
| 노드 식별  | `"question"` or `"animal"` | `is_question` (1/0)      |
| 질문 내용  | `text` 필드에 저장              | `char text[128]`         |
| 하위 노드  | `"yes"`, `"no"`            | `struct Node* yes`, `no` |
| 추가 확장성 | 구조적으로 유연함                  | 메모리 직접 할당 필요             |

### 마무리 정리

> JSON 구조는 웹과 서버에서 다루기 좋고,\
> C 구조체는 시스템 수준에서 메모리를 제어할 수 있어 강력합니다.

## 3. 왜 우리는 브라우저를 떠나 C 코드로 가는가?

웹 브라우저는 마치 고급 리조트처럼 **모든 것을 갖춘 고수준의 환경**입니다. HTML, CSS, 자바스크립트만으로도 유저 인터페이스와 상호작용을 쉽게 구현할 수 있고, `onclick`, `alert`, `appendChild()` 같은 간단한 코드만으로 복잡한 동작이 가능합니다.

하지만…

> 이 "리조트"의 아래층에는 어떤 노동자들이 피땀 흘리며 시스템을 굴리고 있을까요?

우리는 이제 브라우저라는 가상 머신의 안락함을 잠시 떠나, **C 언어로 구현한 터미널 기반의 동물 추측 게임**을 통해, 이 고급 구조의 아래에서 실제로 어떤 일들이 벌어지고 있는지를 들여다보려 합니다.

### 1) 브라우저의 고수준 추상화 구조

```plaintext
[HTML/CSS/JS 코드]
   ↓
[DOM 트리로 변환]
   ↓
[이벤트 루프 & 자바스크립트 인터프리터]
   ↓
[표현 계층 (렌더링 엔진)]
   ↓
[OS I/O, GPU, 사운드 등 하부 인터페이스]
```

* 브라우저는 우리가 직접 다루기 어려운 **I/O, 장치 제어, 입력 처리 등 복잡한 시스템 수준의 요소들**을 모두 감춰줍니다.
* 이런 구조 덕분에 우리는 ‘동물이 짖습니까?’를 화면에 띄우고 버튼만 만들어도, 게임이 실행됩니다.
* 하지만 이 편리함은 대가가 있습니다: 우리가 **무엇을 통제하고 있는지, 어떻게 돌아가는지**는 알 수 없습니다.

### 2) 그래서, C 버전으로 구현한다는 것은?

#### 1. 직접 입력과 출력을 제어해야 합니다

* 브라우저에선 `alert()` 하면 팝업이 뜨지만,
* C에서는 `printf()`로 콘솔에 문자열을 출력하고, `scanf()` 또는 `fgets()`로 입력을 받아야 하죠.
* 입력은 즉각 처리되지 않습니다. 사용자가 **엔터를 눌러야** 버퍼에 저장된 입력을 받을 수 있습니다.

→ 이것이 바로 **Cooked Mode (표준 입력 모드)** 입니다. `Raw Mode`로 바꾸면 엔터 없이 한 글자씩 읽는 것도 가능하지만, 복잡해집니다.

#### 2. 시스템 콜로 OS에 요청해야 합니다

* C에서 `fgets()` 같은 함수를 부르면 내부적으로는 `read()`라는 **시스템 콜**을 호출해 운영체제에게 "입력 줘!"라고 요청합니다.
* 시스템 콜은 일반 함수 호출이 아닙니다. \*\*문맥 전환(context switch)\*\*이 일어나는 중요한 행위입니다.

> 📌 문맥 전환이란?\
> 운영체제는 **현재 프로그램이 요청을 마칠 때까지 기다리는 동안**, **다른 프로그램이 실행될 수 있도록** CPU를 넘깁니다.\
> 이를 위해 **현재 프로그램의 상태(문맥)**&#xB97C; 저장하고, 다른 프로그램의 상태로 **레지스터, 스택 등을 복원**합니다.

#### 3. 드라이버가 키보드/디스플레이와 연결을 흉내 냅니다

* 예전에는 컴퓨터와 키보드를 연결한 케이블이 있었죠. 지금은 이런 선이 **소프트웨어적으로 에뮬레이션**됩니다.
* 터미널 입력을 처리하는 **장치 드라이버**는 입력을 **입력 버퍼에 저장**하고, 화면에는 **에코(echo)** 기능을 통해 사용자 입력을 보여줍니다.
* 드라이버는 ENTER 키가 입력되어야 입력을 사용자 프로그램에게 전달합니다.

### 🔄 입출력 흐름: 전체 흐름도 설명

```plaintext
[사용자 키 입력]
    ↓
[터미널 드라이버의 입력 버퍼에 저장]
    ↓ (ENTER 입력 시)
[운영체제가 사용자 프로그램 깨움]
    ↓
[사용자 프로그램은 버퍼에서 문자열을 읽음]
    ↓
[추론 로직 수행 → 다음 질문 출력]
    ↓
[터미널 출력 버퍼 → 디스플레이]
```

이 흐름이 바로 **표준 I/O (`stdio`) 라이브러리와 장치 드라이버의 협업 구조**입니다.

### 🎯 왜 원형 버퍼가 필요할까?

#### 일반 큐의 문제점

* 일반 FIFO 큐는 데이터를 꺼낼 때마다 **모든 요소를 한 칸씩 앞으로 당겨야** 합니다.
* 계산이 많고 비효율적이죠.

#### 원형 버퍼(Circular Buffer)

* 큐를 **원 모양으로 생각**합니다.
* 앞에서 빼고, 뒤에서 넣고, 인덱스는 `(현재 + 1) % 버퍼 길이`로 계산.
* 공간 재활용이 가능하고, 오버헤드가 적습니다.

```plaintext
g o
r
f
in → 버퍼 추가
out → 버퍼 읽기
```

이 구조는 **장치 드라이버, 네트워크 버퍼, 키보드 입력 처리 등에서 아주 많이 사용**됩니다.

### 📎 표준 입출력 라이브러리 (`stdio`)의 역할

| 역할    | 설명                                          |
| ----- | ------------------------------------------- |
| 입력 버퍼 | 한 번의 시스템 콜로 다량 입력을 받아 메모리에 저장               |
| 출력 버퍼 | 출력 요청이 있을 때까지 데이터 누적 →  등 신호에 맞춰 한 번에 출력    |
| 성능 향상 | 시스템 콜 호출 수를 줄여 문맥 전환 비용 절감                  |
| 구조    | 내부적으로 **링 버퍼 구조** 활용 (FIFO지만 한쪽만 움직이는 큐 형태) |

***

### 🧪 실제 동물 추측 프로그램 예시에서의 흐름 (C 기반)

1. 프로그램 시작
2. 사용자에게 질문 출력 (`printf`)
3. `scanf`로 입력 대기 (ENTER 전까지는 슬립 상태)
4. 대답에 따라 지식 트리 탐색
5. 추측 실패 시, 새로운 동물/질문 입력 받아 지식 트리 확장
6. 루프 반복

지식 트리는 C에서는 동적 구조체로 구현되며, 링크드 트리로 연결됩니다.\
이는 자바스크립트에서 DOM 트리를 사용한 방식과 구조는 비슷하지만, **직접 메모리 할당/해제 (malloc/free)**&#xAC00; 필요합니다.

브라우저에서 아주 쉽게 구현했던 "질문 → 예/아니요 → 다음 질문" 흐름은\
C 기반으로 내려오면 한 단계 한 단계 모두 우리가 직접 짜야 할 구조가 됩니다.

* HTML의 `<div>` 하나가 C에선 구조체 트리의 노드
* `onclick`이벤트가 C에선 사용자 입력을 기다리는 시스템 콜
* `document.appendChild()`가 C에선 `malloc` 후 포인터를 연결하는 트리 확장

### 📌 정리하자면…

| 비교 항목  | 브라우저 환경         | C 터미널 환경                    |
| ------ | --------------- | --------------------------- |
| UI 구성  | HTML 태그         | `printf` 문자열 출력             |
| 트리 구조  | DOM 트리          | 구조체 기반 링크드 트리               |
| 입력 처리  | 버튼 + 이벤트 핸들러    | scanf + 시스템 콜 (read)        |
| 메모리 관리 | 자동              | 수동 (malloc/free)            |
| 버퍼링    | 자동, 거의 신경 안 씀   | 드라이버 버퍼 + stdio 버퍼 직접 고려    |
| 시스템 콜  | 추상화됨            | 직접 호출해야 함 (`read`, `write`) |
| 성능     | 문맥 전환 신경 안 써도 됨 | 문맥 전환 고려 필요 (슬립, 스케줄링 등)    |

## 4. 동물 추측 게임: HTML/CSS/JS vs C 코드 비교 분석

### **1) 프로그램 구조 비교**

| 항목        | 브라우저 기반 (HTML+JS)                | 시스템 기반 (C 터미널)                  |
| --------- | -------------------------------- | ------------------------------- |
| 실행 환경     | 브라우저 (웹페이지)                      | 터미널 (CLI)                       |
| 사용자 인터페이스 | HTML `<button>`, `<input>`       | 콘솔 출력 `printf`, 입력 `scanf`      |
| 지식 트리 구조  | HTML `<div string="질문/동물">` 트리   | 구조체 기반 이진 트리 (노드 구조체)           |
| 트리 저장 방식  | DOM 노드에 숨겨서 저장                   | 메모리 내 구조체 + 포인터                 |
| 이벤트 처리    | `onclick`, `$(selector).click()` | `if/else`, `scanf()` 입력 분기      |
| 상태 전환     | DOM 탐색 및 자식 노드 이동                | 구조체 포인터 이동 (`node = node->yes`) |
| 초기화       | `restart()` 함수                   | 루트 포인터 초기화                      |
| 반복 구조     | 사용자 클릭 이벤트 중심                    | 무한 루프 (`while(1)`)              |
| 메모리 관리    | 자동 (DOM 트리 조작)                   | 수동 (`malloc` / `free`)          |
| 실행 흐름     | 비동기적 인터랙션 (이벤트 루프)               | 동기적 흐름 (입력 → 처리 → 출력)           |

### **2) 지식 트리 구현 코드 비교**

#### 🧱 HTML/JS (브라우저)

```html
<div id="root" class="invisible">
  <div string="동물이 짖습니까?">
    <div string="개"></div>
    <div string="고양이"></div>
  </div>
</div>
```

```js
function question(new_node, html) {
  $('#dialog').append(html);
  if ($(new_node).length == 0) return true;
  node = new_node;
  $('#dialog').append($(node).attr('string') + '?');
  return false;
}
```

* **데이터 구조**: 실제 구조는 HTML DOM, 데이터는 `<div>` 요소의 `string` 속성
* **노드 탐색**: `$(node).children(':first-child')` 식으로 DOM 탐색
* **확장 방식**: `wrap()`과 `prepend()`로 새로운 질문을 삽입

#### ⚙️ C 코드 (터미널)

```c
typedef struct node {
  char *string;
  struct node *yes;
  struct node *no;
} Node;

Node *newNode(char *str) {
  Node *n = malloc(sizeof(Node));
  n->string = strdup(str);
  n->yes = n->no = NULL;
  return n;
}
```

```c
void ask(Node *node) {
  if (node->yes == NULL && node->no == NULL) {
    printf("%s입니까? (y/n) ", node->string);
    char response;
    scanf(" %c", &response);
    if (response == 'y') printf("맞췄습니다!\n");
    else {
      // 새로운 질문/동물 추가...
    }
  } else {
    printf("%s (y/n) ", node->string);
    char response;
    scanf(" %c", &response);
    if (response == 'y') ask(node->yes);
    else ask(node->no);
  }
}
```

* **데이터 구조**: 구조체 기반 이진 트리, `malloc`으로 생성
* **노드 탐색**: 단순한 포인터 이동 (`node->yes`, `node->no`)
* **확장 방식**: `strdup()`으로 문자열 복사 후 새 노드 생성

### **3) 인터페이스 및 I/O 방식 비교**

| 기능       | HTML+JS                           | C (터미널)                                    |
| -------- | --------------------------------- | ------------------------------------------ |
| 입력 방식    | `<button>`, `<input>` 클릭 → 이벤트 발생 | `scanf`, `getchar` 등으로 동기 입력               |
| 출력 방식    | `<div>`에 문자열 append               | `printf()`로 터미널에 출력                        |
| 인터랙션     | 비동기 이벤트 기반 (`click`)              | 순차적 흐름, 입력 없으면 대기                          |
| 문맥 전환    | 브라우저가 처리, 사용자는 인식 못함              | `read()` → 시스템 콜 → 문맥 전환 발생                |
| 시스템 콜 사용 | 브라우저 내부에서 추상화됨                    | `read`, `write`, `malloc`, `free` 등 명시적 호출 |

### **4) 메모리 구조 및 관리 차이**

| 항목        | 브라우저 버전        | C 버전                            |
| --------- | -------------- | ------------------------------- |
| 메모리 할당    | 브라우저가 DOM으로 관리 | 직접 `malloc`, `free` 호출          |
| 트리 저장     | 문서 구조로 자동 저장   | 힙에 노드 구조체로 저장                   |
| 가비지 컬렉션   | 브라우저 GC 자동 처리  | 명시적 메모리 해제 필요                   |
| 메모리 오류 위험 | 낮음             | `메모리 누수`, `dangling pointer` 위험 |

### **5) 핵심 개념 비교 요약표**

| 구분       | 브라우저 환경            | C 환경                    |
| -------- | ------------------ | ----------------------- |
| 프로그래밍 모델 | 선언적 + 이벤트 기반       | 명령형 + 절차적               |
| 데이터 표현   | DOM 엘리먼트 속성        | 구조체 포인터                 |
| 유저 이벤트   | 클릭, 키 입력 → 이벤트 핸들러 | 문자 입력 → 조건 분기           |
| 렌더링      | 브라우저 엔진 자동 처리      | 텍스트 출력만                 |
| 버퍼링      | 브라우저 내부 버퍼 자동      | `stdio`, 드라이버, OS 레벨 버퍼 |
| 디버깅 방식   | 콘솔(log), 브라우저 툴    | gdb, printf 디버깅         |
| 운영체제 추상화 | 거의 완전 추상화          | 운영체제 호출 직접 사용           |
| 코드 복잡도   | 짧고 간단              | 길고 메모리 관리 필요            |

### ✅ 어떤 상황에 어떤 방식이 좋을까?

| 목적             | 브라우저 방식이 유리  | C 방식이 유리         |
| -------------- | ------------ | ---------------- |
| 사용자와 인터랙티브 UI  | ✅ 예          | ❌ 아니요            |
| 시스템 동작 원리 학습   | ❌ 한계 있음      | ✅ 아주 유리          |
| 빠른 프로토타입 제작    | ✅ 빠름         | ❌ 느림             |
| 메모리 최적화 / 고성능  | ❌ 브라우저 한계 있음 | ✅ 가능             |
| 장치 제어, 드라이버 구현 | ❌ 불가능        | ✅ 시스템 직접 접근 가능   |
| 유지보수           | ✅ DOM 트리 활용  | ❌ 포인터/메모리 관리 어려움 |

### 📌 결론

* **브라우저 버전**은 *빠르게 UI를 구성하고 사용자와 상호작용하기에 최적화*되어 있으며, 메모리나 I/O 처리를 브라우저가 도와주므로 학습이 쉬움
* **C 버전**은 *입출력, 버퍼링, 시스템 콜, 문맥 전환 등 시스템 프로그래밍의 핵심 개념을 모두 체험*할 수 있으며, 내부 동작을 정확히 이해하는 데 적합

물론입니다! 아래는 \*\*"추상화를 활용한 코드 개선"\*\*이라는 주제를 바탕으로, 가독성 좋고 스토리텔링 구조로 정리한 콘텐츠입니다.

***

## 🧠 추상화를 활용한 코드 개선 – C와 자바스크립트의 접근 방식 차이

### 1) 상황 설정: 왜 매번 ‘고양이 vs 개’부터 시작할까?

동물 추측 게임을 해본 사람이라면 알겠지만,\
**프로그램을 새로 시작할 때마다 지식 트리가 초기화되며, "개와 고양이" 수준에서 다시 시작**합니다.

"어제는 케르베로스까지 학습했는데..."\
오늘 실행하니 또 개와 고양이만 아는 게임이라면 실망스럽겠죠.

이런 문제를 해결하려면 **이전에 학습된 지식을 저장하고, 다음 실행 시 다시 불러오는 기능**, 즉 `상태의 지속성(persistence)`이 필요합니다.

### 2) C 언어는 어떻게 이걸 해결했나?

C 언어는 이를 꽤 쉽게 해결할 수 있습니다.\
그 이유는 **운영체제 수준의 추상화가 C 언어에 잘 녹아 있기 때문**입니다.

#### ✅ 파일 시스템의 추상화 활용

운영체제는 **파일과 장치를 ‘동일한 인터페이스’로 다루는** 기능을 제공합니다.

> 즉, `파일`에서 읽는 코드 == `키보드 입력`을 받는 코드\
> \=> 둘 다 `fgets()`, `fputs()` 등으로 동일하게 구현 가능

이 덕분에 동물 추측 게임을 C로 만들면,

* 학습 내용을 **파일에 저장(`-o` 옵션)**&#xD558;거나
* 저장된 내용을 **다시 불러와서 이어하기(`-i` 옵션)**&#xAC00; 매우 자연스럽게 구현됩니다.

#### 🎯 예시 흐름

```bash
gta -o training.txt
```

* 사용자가 새 동물과 질문을 입력하면 해당 내용이 `training.txt`에 저장됨
* 다음 실행 시 `gta -i training.txt`로 이전 상태를 불러올 수 있음

이게 가능한 이유는?\
C 프로그램이 파일 시스템의 **입력/출력 추상화**를 직접 활용할 수 있기 때문입니다.

### 3) 브라우저(자바스크립트)는 왜 어려운가?

반면 **브라우저 환경**은 C처럼 직접 시스템 자원을 제어할 수 없습니다.\
왜냐하면 브라우저는 사용자를 보호하기 위해 **보안 모델과 추상화 레이어**를 더 높게 설정해두기 때문이죠.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FgQFL4Wp7t5onbPsUGmCN%2Fimage.png?alt=media&#x26;token=b7fdd298-9b45-413d-9c0c-44114e160910" alt=""><figcaption></figcaption></figure>

#### ❌ 추상화가 ‘숨겨져 있는’ 구조

아래 그림처럼,\
브라우저에서는 파일 시스템과 직접 연결되는 코드가 없습니다.

```
사용자 코드      →       브라우저 API      →     운영체제 I/O

       X                   O                   O
```

#### ❗ 불편한 점

* 파일 시스템에 접근하려면 File API, IndexedDB, LocalStorage 등 완전히 별개의 API를 써야 함
* 이 API들은 일관된 입출력 인터페이스가 아닌 **완전히 다른 설계철학**을 가짐
* 따라서 게임의 상태 저장 기능을 추가하려면 **완전히 다른 방식의 코드**를 새로 작성해야 함

### 4) 요약 비교

| 항목            | C 프로그램                      | 자바스크립트 (브라우저)                       |
| ------------- | --------------------------- | ----------------------------------- |
| 시스템 접근        | 파일/장치 모두 동일한 인터페이스          | 제한적 접근만 허용                          |
| 상태 저장 방식      | `fopen`, `fgets`, `fputs` 등 | LocalStorage, IndexedDB 등 별도 API 필요 |
| 학습 지속성 구현 난이도 | 낮음 (파일만 다루면 됨)              | 높음 (추가 기술 학습 필요)                    |
| 장점            | 단순한 코드로 다양한 입력/출력 구현 가능     | 사용자 보안에 강함, 크로스 플랫폼 환경              |
| 단점            | 시스템 자원 접근 제한 없음 → 보안 위험     | 동일 기능 구현 시 API 다양하고 복잡함             |

### 5) 🌐 프로그래밍 언어 설계에 대한 교훈

프로그래밍 언어와 플랫폼은 **어떤 추상화를 어떻게 드러낼 것인가**에 따라 생산성과 편의성이 달라집니다.

* C는 "시스템에 가깝게 일하자"는 철학 아래, **입출력과 파일 시스템을 통합된 인터페이스로 제공**합니다.
* 브라우저는 보안과 유저 편의를 중시하며, **다양한 추상화를 개발자에게서 숨기고, 대신 안전한 고수준 API를 제공합니다.**

이로 인해 **동일한 기능이라도 완전히 다른 방식으로 구현**되며, 추상화 수준에 따라 **코드의 유연성과 재사용성도 달라집니다.**

## 📦 런타임 라이브러리와 표준 입출력: 시스템 프로그래밍의 시작점

### 1) 프로그램이 실행되기까지 – 우리가 보지 못한 준비 작업들

C로 작성한 프로그램이 `./a.out`이나 `gta` 같은 이름으로 실행되는 순간, 단순히 메인 함수부터 실행되는 것 같지만, 실제로는 **그 이전에 아주 중요한 준비 작업**이 일어납니다.

> 이걸 담당하는 게 바로 **런타임 라이브러리(runtime library)** 입니다.

#### 🛠️ 런타임 라이브러리가 하는 일

* **스택과 힙** 메모리 공간 초기화
* 표준 입출력 시스템을 위한 장치 파일 오픈
* `stdin`, `stdout`, `stderr` 같은 **기본 입출력 핸들** 준비

이런 준비가 없으면 `printf`, `scanf`, `fgets` 같은 함수는 사용할 수 없습니다. C에서는 이 준비가 **`crt0`** 또는 `crt1.o`라는 스타트업 코드(startup object)에서 자동으로 수행됩니다.

### 2) stdio: C에서 가장 널리 쓰이는 라이브러리

#### 📍 stdio의 핵심 개념: 버퍼링된 입출력

표준 입출력 라이브러리는 다음과 같은 **세 가지 주요 포인터**를 제공합니다:

| 이름       | 설명       | 디스크립터 |
| -------- | -------- | ----- |
| `stdin`  | 표준 입력    | 0     |
| `stdout` | 표준 출력    | 1     |
| `stderr` | 표준 오류 출력 | 2     |

#### 🤔 `stdout`과 `stderr`의 차이는?

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F1mrbzxvD5T77ox1P9YG5%2Fimage.png?alt=media&#x26;token=dcd402ac-a61b-4e07-bc0a-352b904d06dc" alt=""><figcaption></figcaption></figure>

* 둘 다 **콘솔로 출력**됨
* 하지만 **버퍼링 방식이 다름**:
  * `stdout`: **라인 버퍼** → 줄 바꿈 전까지 저장되며, 프로그램이 중단되면 유실될 수도 있음
  * `stderr`: **비버퍼링** → 즉시 출력됨

따라서 오류 메시지는 항상 `stderr`로 출력하는 게 안전합니다.

**📌 재밌는 역사적 배경**

초기의 `사진 조판 장치(C/A/T)`는 조판된 문서를 출력하기까지 비용이 많이 들었기 때문에, 단순한 오류 메시지(예: “파일을 열 수 없습니다”)를 조판 프린터로 출력하지 않고 **터미널로 따로 보내기 위해 `stderr`가 생겼습니다.**

### 3) 시스템 프로그래밍의 어두운 그림자 – 버퍼 오버플로

#### 💣 `gets()`의 위험한 함정

초기 C 라이브러리에는 `gets(char *buffer)`라는 아주 간단한 입력 함수가 있었습니다.\
하지만 **이 함수는 치명적인 단점을 안고 있었습니다**.

```c
char buffer[2];
gets(buffer);  // 👈 문제 발생
```

* `gets()`는 입력받는 문자열의 **길이를 제한하지 않음**
* 사용자 입력이 `buffer`의 크기를 초과하면? → **메모리 침범**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FzyeIIxFciJig8M7cGao0%2Fimage.png?alt=media&#x26;token=8d941e75-2e59-47f2-91b4-4a288dbb6253" alt=""><figcaption></figcaption></figure>

**🚨 실제 위협 사례**

{% hint style="danger" %}
만약 `buffer` 뒤에 민감한 데이터(예: `launch_missiles`)가 위치한다면,\
`yyy`와 같은 입력으로 **코드를 조작하거나 시스템을 위협**할 수 있습니다.
{% endhint %}

이런 취약점은 **수많은 보안 사고**로 이어졌고,\
C99 이후로는 `gets()`가 **사용금지(deprecated)** 되었으며,\
C11에서는 **완전히 삭제**되었습니다.

✅ 안전한 대안: `fgets(buffer, sizeof(buffer), stdin)`

버퍼 오버플로가 발생할 시 버퍼에 다 담지 못한 값들은 버퍼 이후의 공간에 들어차게 됩니다. 문제는 들어차는 방식이 밀어내기가 아닌 **덮어쓰기**라는 것입니다.\
\
가령 8칸짜리 메모리가 있고, 그 안에 4칸짜리 버퍼가 있을 때

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FStnki97sk8eTeLQstW1a%2Fimage.png?alt=media&#x26;token=9dd8eb83-3069-4306-9a6f-95e41e05271b" alt=""><figcaption><p><a href="https://namu.wiki/w/%EB%B2%84%ED%8D%BC%20%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C">https://namu.wiki/w/%EB%B2%84%ED%8D%BC%20%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C</a></p></figcaption></figure>

> 이와 같이 사용자가 버퍼를 초과하는 값을 입력하면 버퍼 이후의 값이 바뀌게 된다.\
> \
> 문제는 이걸 프로그램은 **전혀 모르고 있는 상태**라는 것이다. 심지어 버퍼 이후의 값이 바뀌어도 프로그램은 이를 전혀 사용자에게 통지하지 않는다!
>
> ⇒ 물론 이는 로우 레벨까지 [프로그래머](https://namu.wiki/w/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8)가 [세세하게 코딩해야 했던 때](https://namu.wiki/w/C%EC%96%B8%EC%96%B4)의 이야기고 요즘은 디버깅시 컴파일러가 버퍼 앞뒤에 오버플로 방어용 1\~4바이트짜리 값을 넣어(카나리라고 한다. 어원은 [카나리아(조류)](https://namu.wiki/w/%EC%B9%B4%EB%82%98%EB%A6%AC%EC%95%84\(%EC%A1%B0%EB%A5%98\)) 문서 참조) 침범되었을 경우 [예외](https://namu.wiki/w/%EC%98%88%EC%99%B8%20%EC%B2%98%EB%A6%AC)를 때려버리거나 코딩 단계에서 '이 함수는 버퍼 오버플로의 위험이 있음' 이라고 경고를 해 준다. 물론 이 현상이 사라진 건 아니므로 [프로그래머](https://namu.wiki/w/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8)는 여전히 버퍼에 들어가는 값을 체크 해야 된다.\
> \
> 중요하지 않은 10줄\~50줄짜리 소규모 예제 [프로그램](https://namu.wiki/w/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8)이라면 이는 딱히 신경쓰지 않아도 되지만 중형이나 <mark style="color:red;">대규모 프로젝트라면 이야기가 달라지는데 이 원리를 통해</mark> [<mark style="color:red;">**해킹**</mark>](https://namu.wiki/w/%ED%95%B4%ED%82%B9)<mark style="color:red;">**이 가능하기 때문이다.**</mark>\
> \
> 간단한 예를 들자면 10자리 비밀번호를 치고 들어가는 시스템이 있다고 하자. 그리고 비밀번호를 저장하는 값 바로 뒤에 로그인 여부를 묻는 값이 있다고 하자.(0=실패, 이외의 값=성공) 이 상황에서 끝자리가 <mark style="color:blue;">0이 아닌 11자리 비밀번호를 입력하면 틀리더라도 뚫을 수 있게 된다!</mark>\
> \
> 만약 버퍼를 초과하여 쓰이는 값이 [프로그램](https://namu.wiki/w/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8)의 RETN[\[4\]](https://namu.wiki/w/%EB%B2%84%ED%8D%BC%20%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C#fn-4)값을 덮어쓰게 된다면 사용자가 프로그램의 진행 상황을 통제할 수 있게 된다. 만약 특정한 [함수](https://namu.wiki/w/%ED%95%A8%EC%88%98)가 있고, 이 [함수](https://namu.wiki/w/%ED%95%A8%EC%88%98)의 주솟값을 알고 어떤 입력이 버퍼 오버플로 공격이 가능하다면 그냥 '입력받는 문자열 + 4[\[5\]](https://namu.wiki/w/%EB%B2%84%ED%8D%BC%20%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C#fn-5)/8[\[6\]](https://namu.wiki/w/%EB%B2%84%ED%8D%BC%20%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C#fn-6)바이트(SFP 덮어쓰기용) + 해당 함수 주소'를 입력값에 쑤셔넣어 입력 함수가 끝나면 자신이 원하는 함수로 점프할 수 있게 된다.\
> \
> 가장 유명한 사례로는 [하트블리드 사태](https://namu.wiki/w/%ED%95%98%ED%8A%B8%EB%B8%94%EB%A6%AC%EB%93%9C%20%EC%82%AC%ED%83%9C)와 스타크래프트 1의 [EUD](https://namu.wiki/w/EUD)가 있다.\
> \
> \- 나무 위키 -&#x20;

### 4) 메모리와 포인터를 사용하는 C 구조체 – 노드 구조 선언

자바스크립트에서는 DOM `<div>` 구조를 활용해 트리를 만들었지만,\
C에서는 좀 더 직접적인 방식으로 **메모리와 포인터**를 활용합니다.

```c
struct node {
  struct node *no;
  struct node *yes;
  char string[1];
};
```

* `no`, `yes`는 **왼쪽/오른쪽 자식 노드**
* `string`은 **동물 이름이나 질문**

#### 💡 메모리 할당 방식

C에서는 문자열을 담기 위해 노드 구조체 크기 + 문자열 길이만큼 `malloc`을 사용해 **직접 메모리를 계산하여 할당**합니다.

```c
malloc(sizeof(struct node) + strlen(string))
```

이런 **저수준 메모리 제어**는 위험하지만 강력하며, 시스템 프로그래밍에서 아주 중요한 능력입니다.

### 🧾 정리: 런타임, 입출력, 보안까지 이어지는 시스템 세계

| 항목                   | 설명                           |
| -------------------- | ---------------------------- |
| 런타임 라이브러리            | 실행 전에 메모리 구조와 파일 핸들을 초기화     |
| `stdio`              | 입력/출력과 버퍼링을 다루는 표준 I/O 라이브러리 |
| `stdout` vs `stderr` | 출력 방식의 차이로 오류 메시지 관리         |
| `gets()`와 `fgets()`  | 버퍼 오버플로와 그로 인한 보안 위협         |
| 구조체 + 포인터            | 자바스크립트보다 더 직접적인 메모리 조작 방식    |

***

## 🧠 주제: 고수준과 저수준 프로그램의 경계에서 – 자바스크립트 vs C로 구현한 ‘동물 추측 게임’ 비교

### 1) **프로그램 구조와 실행 환경 비교**

| 구분           | HTML/JavaScript               | C 언어                              |
| ------------ | ----------------------------- | --------------------------------- |
| **실행 환경**    | 브라우저 (V8 엔진 포함)               | OS에서 직접 실행 (터미널 기반)               |
| **입출력 방식**   | 브라우저 제공 Web API, DOM, 이벤트 핸들러 | stdin, stdout, stderr 및 파일 입출력 함수 |
| **UI 처리**    | 버튼, 텍스트 입력, HTML DOM으로 구현     | 텍스트 기반 y/n/q 입력 처리                |
| **지식 트리 구조** | `<div>`를 트리 구조로 활용            | `struct node` 기반 동적 메모리 구조        |
| **게임 상태 저장** | 브라우저 내부에서는 어려움                | 파일 입출력 (옵션으로 -i, -o)              |
| **프로그램 흐름**  | jQuery 및 JS 이벤트 기반 처리         | 루프, 조건문, 포인터 중심의 구조적 처리           |

### 2) **입출력 추상화의 차이**

* **브라우저(JavaScript)**:
  * 파일 접근 제한 (보안상 이유로 local file 접근 어려움)
  * Web API로 입출력 추상화
  * 브라우저가 많은 세부 사항을 감춤 (파일, 터미널 존재 X)
* **C 언어**:
  * 파일/장치 구분 없음 → 동일한 인터페이스 제공
  * `fopen`, `fgets`, `fputs` 등의 표준 입출력 함수로 데이터 처리
  * stderr는 버퍼링을 하지 않기 때문에 중요한 메시지 출력에 사용

> 브라우저에서 새 기능을 추가하려면 “완전히 다른 API”를 써야 하지만, C에서는 장치와 파일이 같은 인터페이스를 공유하기 때문에 재사용이 용이합니다.

### 3) **메모리와 자료구조 구현 비교**

| 항목         | JavaScript                   | C 언어                         |
| ---------- | ---------------------------- | ---------------------------- |
| **노드 구조**  | `<div string="질문">...</div>` | `struct node` with string\[] |
| **메모리 할당** | 브라우저 내부 메커니즘 사용              | `malloc`으로 수동 할당             |
| **문자열 처리** | JS 내장 문자열 함수                 | `strcpy`, `strlen` 등 직접 처리   |
| **포인터 사용** | 없음 (참조 기반)                   | yes/no → 포인터 직접 연결           |

> 자바스크립트에서는 `<div>` DOM 요소가 곧 트리 노드이자 데이터를 품은 객체입니다. C에서는 이를 명시적으로 구조체와 포인터로 구현해야 하며, 메모리 할당도 직접 해줘야 합니다.

### 4) **버퍼링과 표준 입출력 구조**

#### stdin / stdout / stderr 구조

* **stdin**: 사용자의 입력을 받음
* **stdout**: 일반 메시지 출력
* **stderr**: 오류 메시지 출력 (버퍼링 없음)

```c
char buffer[2];
gets(buffer); // 위험: 버퍼 오버플로 가능
```

> gets는 더 이상 사용되지 않으며, 버퍼 크기를 지정할 수 있는 `fgets()`로 대체됩니다. 버퍼 오버플로 취약점은 보안 측면에서 큰 이슈입니다.

#### 🎯 버퍼 오버플로 예시

```c
char buffer[2];
gets(buffer);  // yyy 입력 → launch_missiles 변수에 영향 가능
```

**→ 대응법:**

```c
fgets(buffer, sizeof(buffer), stdin);
```

### 5) **훈련 기능 구현 차이**

* **JavaScript**:
  * 브라우저에 훈련 데이터 저장 어려움
  * 로컬스토리지 또는 백엔드 서버 연동 필요
* **C 프로그램**:
  * `-i`, `-o` 옵션으로 파일 입출력 기능 구현
  * `fopen`, `fputs`, `fgets` 등으로 데이터 저장

> 훈련 데이터를 파일에 저장한 뒤 다음 게임에서 이어서 불러오는 기능은 CLI에서 훨씬 자연스럽게 구현됩니다.

## ✨ 마무리: 왜 두 코드는 같은 게임인데 이렇게 다를까?

* 브라우저 기반 앱은 사용자 인터페이스(UI)를 자동으로 제공하지만, 시스템 자원 접근에는 제한이 많습니다.
* 반면 C로 구현된 CLI 버전은 모든 것을 직접 구현해야 하지만, 파일과 장치를 같은 방식으로 다룰 수 있어 확장성이 좋습니다.
* 추상화의 차이는 곧 개발 방식과 성능, 유지보수에 큰 영향을 미칩니다.
