애플리케이션 프로그래밍과 시스템 프로그래밍
고수준 언어와 저수준 언어 프로그래밍 방식 비교
Last updated
고수준 언어와 저수준 언어 프로그래밍 방식 비교
Last updated
우리는 지난 장까지 브라우저를 마치 고차원의 가상 컴퓨터처럼 바라봤어요.
즉, 브라우저는 HTML, CSS, JavaScript 등 '명령어'를 받아서 DOM(Document Object Model)
을 조작하는 구조입니다.
DOM API
이벤트 핸들러
Ajax / Fetch 등 통신 API
이러한 고수준 API는 운영체제와 I/O 장치의 복잡성을 감춰줍니다.
그럼 이번 장에서는 브라우저를 거치지 않고 같은 프로그램을 만들면 어떻게 다를지 직접 비교해 봅시다.
👉 웹 브라우저 기반은 사용자가 다루기 쉽고 빠르게 만들 수 있습니다. 👉 시스템 수준 프로그래밍(C 언어 등)은 하드웨어와 OS 동작을 더 정확히 이해하고 제어할 수 있습니다.
우리가 만든 프로그램은 사용자가 생각한 동물을 컴퓨터가 질문을 통해 추측하는 간단한 지식 기반 게임입니다.
질문을 통해 트리 구조를 따라 내려감
잎(Leaf) 노드에 도달하면 동물을 추측
추측 실패 시 새로운 동물과 질문을 받아 트리 확장
다음 라운드부터는 더 똑똑해짐 (학습함)
그림을 보면 동물에 대한 지식으로 이뤄진 트리를 따라 내려가되, 질문을 던지면서 어느 경로로 내려갈지를 결정합니다.
제대로 동물을 추측하면 기뻐한다.
동물을 맞히지 못하면 사용자에게 정 답을 물어본 후 해당 동물을 마지막에 확인한 동물과 구분하는 데 필요한 질문을 요청해서, 그 정보를 트리에 추가하고 처음부터 다시 시작한다.
이 프로그램은 (순서도의 왼쪽에서) 지식 트리를 따라 내려가면서 질문을 던지고 답을 얻습니다.
오른쪽에서 경로의 끝에 도달하면 답을 맞혔는지 여부에 따라 잘난 체를 하거나 동물에 대한 지 식을 지식 기반knowledge base에 추가합니다.
이 순서도를 코드로 바꾸면 아래와 같은 흐름이 됩니다:
사용자 인터페이스
HTML + CSS + DOM 조작
콘솔 출력, scanf/printf
데이터 저장
LocalStorage, 서버
파일 I/O, 메모리 직접 제어
입력 처리
prompt
, click
이벤트
scanf
, getchar()
등
확장성
빠르고 직관적
복잡하지만 강력함
웹 브라우저는 이미 많은 기능이 추상화되어 있지만, 시스템 프로그래밍은 메모리, 파일, 버퍼 등 세세한 부분까지 관리해야 합니다.
앞서 요청하신 예시 흐름도도 아래와 같이 이어집니다.
→ 이 흐름은 현대적인 SPA 프레임워크에서 CRUD 처리의 전형적인 구조입니다.
브라우저가 '컴퓨터 같은 프로그램'이라는 비유
고수준 프로그래머는 DOM API만 알면 되지만, 시스템 프로그래머는 '그 아래'까지 봐야 합니다.
동물 맞히기 게임은 질문을 던지고 그에 따라 예/아니오로 가지를 뻗는 이진 트리 구조를 사용합니다.
예:
질문 노드는 "question"
키를 가짐
동물(잎 노드)은 "animal"
키만 있음
"yes"
, "no"
로 자식 노드를 연결
노드 식별
"question"
or "animal"
is_question
(1/0)
질문 내용
text
필드에 저장
char text[128]
하위 노드
"yes"
, "no"
struct Node* yes
, no
추가 확장성
구조적으로 유연함
메모리 직접 할당 필요
JSON 구조는 웹과 서버에서 다루기 좋고, C 구조체는 시스템 수준에서 메모리를 제어할 수 있어 강력합니다.
웹 브라우저는 마치 고급 리조트처럼 모든 것을 갖춘 고수준의 환경입니다. HTML, CSS, 자바스크립트만으로도 유저 인터페이스와 상호작용을 쉽게 구현할 수 있고, onclick
, alert
, appendChild()
같은 간단한 코드만으로 복잡한 동작이 가능합니다.
하지만…
이 "리조트"의 아래층에는 어떤 노동자들이 피땀 흘리며 시스템을 굴리고 있을까요?
우리는 이제 브라우저라는 가상 머신의 안락함을 잠시 떠나, C 언어로 구현한 터미널 기반의 동물 추측 게임을 통해, 이 고급 구조의 아래에서 실제로 어떤 일들이 벌어지고 있는지를 들여다보려 합니다.
브라우저는 우리가 직접 다루기 어려운 I/O, 장치 제어, 입력 처리 등 복잡한 시스템 수준의 요소들을 모두 감춰줍니다.
이런 구조 덕분에 우리는 ‘동물이 짖습니까?’를 화면에 띄우고 버튼만 만들어도, 게임이 실행됩니다.
하지만 이 편리함은 대가가 있습니다: 우리가 무엇을 통제하고 있는지, 어떻게 돌아가는지는 알 수 없습니다.
브라우저에선 alert()
하면 팝업이 뜨지만,
C에서는 printf()
로 콘솔에 문자열을 출력하고, scanf()
또는 fgets()
로 입력을 받아야 하죠.
입력은 즉각 처리되지 않습니다. 사용자가 엔터를 눌러야 버퍼에 저장된 입력을 받을 수 있습니다.
→ 이것이 바로 Cooked Mode (표준 입력 모드) 입니다. Raw Mode
로 바꾸면 엔터 없이 한 글자씩 읽는 것도 가능하지만, 복잡해집니다.
C에서 fgets()
같은 함수를 부르면 내부적으로는 read()
라는 시스템 콜을 호출해 운영체제에게 "입력 줘!"라고 요청합니다.
시스템 콜은 일반 함수 호출이 아닙니다. **문맥 전환(context switch)**이 일어나는 중요한 행위입니다.
📌 문맥 전환이란? 운영체제는 현재 프로그램이 요청을 마칠 때까지 기다리는 동안, 다른 프로그램이 실행될 수 있도록 CPU를 넘깁니다. 이를 위해 현재 프로그램의 상태(문맥)를 저장하고, 다른 프로그램의 상태로 레지스터, 스택 등을 복원합니다.
예전에는 컴퓨터와 키보드를 연결한 케이블이 있었죠. 지금은 이런 선이 소프트웨어적으로 에뮬레이션됩니다.
터미널 입력을 처리하는 장치 드라이버는 입력을 입력 버퍼에 저장하고, 화면에는 에코(echo) 기능을 통해 사용자 입력을 보여줍니다.
드라이버는 ENTER 키가 입력되어야 입력을 사용자 프로그램에게 전달합니다.
이 흐름이 바로 표준 I/O (stdio
) 라이브러리와 장치 드라이버의 협업 구조입니다.
일반 FIFO 큐는 데이터를 꺼낼 때마다 모든 요소를 한 칸씩 앞으로 당겨야 합니다.
계산이 많고 비효율적이죠.
큐를 원 모양으로 생각합니다.
앞에서 빼고, 뒤에서 넣고, 인덱스는 (현재 + 1) % 버퍼 길이
로 계산.
공간 재활용이 가능하고, 오버헤드가 적습니다.
이 구조는 장치 드라이버, 네트워크 버퍼, 키보드 입력 처리 등에서 아주 많이 사용됩니다.
stdio
)의 역할입력 버퍼
한 번의 시스템 콜로 다량 입력을 받아 메모리에 저장
출력 버퍼
출력 요청이 있을 때까지 데이터 누적 → 등 신호에 맞춰 한 번에 출력
성능 향상
시스템 콜 호출 수를 줄여 문맥 전환 비용 절감
구조
내부적으로 링 버퍼 구조 활용 (FIFO지만 한쪽만 움직이는 큐 형태)
프로그램 시작
사용자에게 질문 출력 (printf
)
scanf
로 입력 대기 (ENTER 전까지는 슬립 상태)
대답에 따라 지식 트리 탐색
추측 실패 시, 새로운 동물/질문 입력 받아 지식 트리 확장
루프 반복
지식 트리는 C에서는 동적 구조체로 구현되며, 링크드 트리로 연결됩니다. 이는 자바스크립트에서 DOM 트리를 사용한 방식과 구조는 비슷하지만, 직접 메모리 할당/해제 (malloc/free)가 필요합니다.
브라우저에서 아주 쉽게 구현했던 "질문 → 예/아니요 → 다음 질문" 흐름은 C 기반으로 내려오면 한 단계 한 단계 모두 우리가 직접 짜야 할 구조가 됩니다.
HTML의 <div>
하나가 C에선 구조체 트리의 노드
onclick
이벤트가 C에선 사용자 입력을 기다리는 시스템 콜
document.appendChild()
가 C에선 malloc
후 포인터를 연결하는 트리 확장
UI 구성
HTML 태그
printf
문자열 출력
트리 구조
DOM 트리
구조체 기반 링크드 트리
입력 처리
버튼 + 이벤트 핸들러
scanf + 시스템 콜 (read)
메모리 관리
자동
수동 (malloc/free)
버퍼링
자동, 거의 신경 안 씀
드라이버 버퍼 + stdio 버퍼 직접 고려
시스템 콜
추상화됨
직접 호출해야 함 (read
, write
)
성능
문맥 전환 신경 안 써도 됨
문맥 전환 고려 필요 (슬립, 스케줄링 등)
실행 환경
브라우저 (웹페이지)
터미널 (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
)
실행 흐름
비동기적 인터랙션 (이벤트 루프)
동기적 흐름 (입력 → 처리 → 출력)
데이터 구조: 실제 구조는 HTML DOM, 데이터는 <div>
요소의 string
속성
노드 탐색: $(node).children(':first-child')
식으로 DOM 탐색
확장 방식: wrap()
과 prepend()
로 새로운 질문을 삽입
데이터 구조: 구조체 기반 이진 트리, malloc
으로 생성
노드 탐색: 단순한 포인터 이동 (node->yes
, node->no
)
확장 방식: strdup()
으로 문자열 복사 후 새 노드 생성
입력 방식
<button>
, <input>
클릭 → 이벤트 발생
scanf
, getchar
등으로 동기 입력
출력 방식
<div>
에 문자열 append
printf()
로 터미널에 출력
인터랙션
비동기 이벤트 기반 (click
)
순차적 흐름, 입력 없으면 대기
문맥 전환
브라우저가 처리, 사용자는 인식 못함
read()
→ 시스템 콜 → 문맥 전환 발생
시스템 콜 사용
브라우저 내부에서 추상화됨
read
, write
, malloc
, free
등 명시적 호출
메모리 할당
브라우저가 DOM으로 관리
직접 malloc
, free
호출
트리 저장
문서 구조로 자동 저장
힙에 노드 구조체로 저장
가비지 컬렉션
브라우저 GC 자동 처리
명시적 메모리 해제 필요
메모리 오류 위험
낮음
메모리 누수
, dangling pointer
위험
프로그래밍 모델
선언적 + 이벤트 기반
명령형 + 절차적
데이터 표현
DOM 엘리먼트 속성
구조체 포인터
유저 이벤트
클릭, 키 입력 → 이벤트 핸들러
문자 입력 → 조건 분기
렌더링
브라우저 엔진 자동 처리
텍스트 출력만
버퍼링
브라우저 내부 버퍼 자동
stdio
, 드라이버, OS 레벨 버퍼
디버깅 방식
콘솔(log), 브라우저 툴
gdb, printf 디버깅
운영체제 추상화
거의 완전 추상화
운영체제 호출 직접 사용
코드 복잡도
짧고 간단
길고 메모리 관리 필요
사용자와 인터랙티브 UI
✅ 예
❌ 아니요
시스템 동작 원리 학습
❌ 한계 있음
✅ 아주 유리
빠른 프로토타입 제작
✅ 빠름
❌ 느림
메모리 최적화 / 고성능
❌ 브라우저 한계 있음
✅ 가능
장치 제어, 드라이버 구현
❌ 불가능
✅ 시스템 직접 접근 가능
유지보수
✅ DOM 트리 활용
❌ 포인터/메모리 관리 어려움
브라우저 버전은 빠르게 UI를 구성하고 사용자와 상호작용하기에 최적화되어 있으며, 메모리나 I/O 처리를 브라우저가 도와주므로 학습이 쉬움
C 버전은 입출력, 버퍼링, 시스템 콜, 문맥 전환 등 시스템 프로그래밍의 핵심 개념을 모두 체험할 수 있으며, 내부 동작을 정확히 이해하는 데 적합