C 언어 프로그램은 어떻게 실행될까?
한 문장 요약
C 코드 → 컴파일 → 기계어(바이너리) → 운영체제가 CPU에서 직접 실행
📚 배경 개념
프로그래밍 언어의 두 가지 방식
┌──────────────────────────┐
│ 컴파일 언어 (Compiled) │
├──────────────────────────┤
│ C, C++, Go, Rust │
│ │
│ 특징: │
│ - 사전에 기계어로 변환 │
│ - 속도 매우 빠름 │
│ - 실행 전 에러 감지 │
└──────────────────────────┘
┌──────────────────────────┐
│ 인터프리터 언어 (Interpreted)│
├──────────────────────────┤
│ Python, JavaScript, Ruby │
│ │
│ 특징: │
│ - 실행 중에 해석 │
│ - 개발 속도 빠름 │
│ - 느린 실행 속도 │
└──────────────────────────┘
⚙️ 컴파일 과정 (C 언어 예시)
전체 흐름
┌──────────────────────────────┐
│ 1️⃣ 소스 코드 작성 │
│ (database.c) │
│ - 인간이 읽을 수 있는 C 코드 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 2️⃣ 컴파일러 (gcc, clang) │
│ - C 코드 문법 검사 │
│ - C 코드를 기계어로 변환 │
│ - 최적화 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 3️⃣ 바이너리 파일 │
│ (postgresql 실행 파일) │
│ - 기계어 (0101101...) │
│ - CPU가 직접 실행 가능 │
│ - .exe (Windows) │
│ - (macOS, Linux) │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ 4️⃣ 운영체제 (OS) │
│ - 바이너리를 메모리에 로드 │
│ - CPU에서 기계어 실행 │
└──────────────────────────────┘
💻 구체적인 예시
PostgreSQL 컴파일 과정
# 1️⃣ 소스 파일들
src/backend/parser/parse.c
src/backend/executor/execMain.c
src/backend/storage/file/bufmgr.c
... (1000개 이상의 .c 파일)
# 2️⃣ 컴파일
$ gcc -O2 src/backend/*.c -o postgresql
# 과정:
# - 각 .c 파일을 .o (오브젝트) 파일로 변환
# - 모든 .o 파일을 링크
# - 최적화 (-O2 플래그)
# 3️⃣ 결과
postgresql (바이너리 실행 파일)
├─ 크기: ~50MB
├─ 내용: 기계어 명령어
└─ 구성: CPU가 이해하는 바이너리
# 4️⃣ 실행
$ ./postgresql
또는
$ postgres -D /data/postgres🔍 C 언어와 기계어의 관계
C 코드 vs 기계어
C 코드 (인간이 읽음)
// C 코드
int sum(int a, int b) {
return a + b;
}기계어 (CPU가 읽음)
; x86-64 어셈블리 (기계어를 사람이 읽을 수 있게)
sum:
add edi, esi ; a + b 연산
mov eax, edi ; 결과를 반환 레지스터에
ret ; 함수 반환실제 바이너리 (CPU가 읽음)
01100101 01110001
01001000 10010100
... (0과 1의 나열)
🚀 컴파일 vs 인터프리터 성능 비교
실행 속도
┌──────────────────────────────────┐
│ 컴파일 언어 (C) │
│ [컴파일] → [실행] │
│ 느림 빠름 │
│ │
│ 프로그램 실행 시간: 0.001초 ⚡⚡⚡ │
└──────────────────────────────────┘
┌──────────────────────────────────┐
│ 인터프리터 언어 (Python) │
│ [인터프리터 시작] │
│ [라인별 해석] → [실행] │
│ 빠름 느림 │
│ │
│ 프로그램 실행 시간: 0.05초 ⚡ │
└──────────────────────────────────┘
백만 개 정수 합계:
C 언어: 0.002초 ⚡⚡⚡
Python: 0.052초 ⚡
50배 빠름!
🐍 CPython의 경우 (Python은 인터프리터인데?)
CPython = C로 만들어진 인터프리터
┌────────────────────────────────┐
│ Python 코드 (script.py) │
│ def sum(a, b): │
│ return a + b │
└──────────────┬─────────────────┘
│
┌──────────────▼─────────────────┐
│ CPython (C로 작성된 인터프리터) │
│ │
│ [Python 코드 해석] │
│ ├─ 문법 검사 │
│ ├─ 바이트코드 생성 │
│ └─ 바이트코드 실행 │
└──────────────┬─────────────────┘
│
┌──────────────▼─────────────────┐
│ 결과 │
│ 3 (sum(1, 2)의 결과) │
└────────────────────────────────┘
핵심:
- CPython은 C로 컴파일된 프로그램
- 하지만 Python 코드는 런타임에 해석됨
- 그래서 Python은 느림
📊 언어별 실행 방식 비교
| 언어 | 컴파일 방식 | 작성 언어 | 실행 방식 | 속도 |
|---|---|---|---|---|
| C | 컴파일 | C | CPU 직접 실행 | ⚡⚡⚡ 빠름 |
| Go | 컴파일 | Go | CPU 직접 실행 | ⚡⚡⚡ 빠름 |
| Java | 컴파일 → 바이트코드 | Java | JVM 해석 | ⚡⚡ 중간 |
| Python | 없음 | Python | CPython 해석 | ⚡ 느림 |
| JavaScript | 없음 | JavaScript | V8/Node 해석 | ⚡ 느림 |
🎯 왜 PostgreSQL과 MySQL은 C로 만들어졌나?
성능이 중요한 이유
데이터베이스는 초당 수천 개의 쿼리를 처리해야 함
↓
각 쿼리가 빨라야 함
↓
C 언어로 컴파일해서 CPU 직접 실행
↓
Python/Java보다 50-100배 빠름
선택지
❌ Python으로 DB 엔진 만들기
- 초당 10 쿼리 처리
- 1000명 동시 접속 불가능
✅ C로 DB 엔진 만들기
- 초당 10,000 쿼리 처리
- 1000명 동시 접속 가능
🔗 컴파일과 드라이버의 관계
드라이버도 C로 컴파일됨
┌────────────────────────────────┐
│ JDBC 드라이버 (Java) │
│ - Java로 작성 │
│ - JVM에서 실행 │
│ → 약간 느림 │
└────────────────────────────────┘
┌────────────────────────────────┐
│ libpq 드라이버 (C) │
│ - C로 작성 │
│ - 컴파일되어 실행 │
│ → 매우 빠름 │
└────────────────────────────────┘
결과:
- C 드라이버 + C 엔진 = 초고속 ⚡⚡⚡
- Java 드라이버 + C 엔진 = 중간 ⚡⚡
💡 핵심 요약
컴파일 과정
C 소스 코드
↓ (컴파일러)
기계어 바이너리
↓ (운영체제)
CPU 직접 실행
↓
초고속 ⚡⚡⚡
인터프리터 과정
Python 소스 코드
↓ (CPython 인터프리터)
라인별 해석 & 실행
↓
느림 ⚡
🔗 관련 개념
다음 단계:
- 소프트웨어 아키텍처 용어 - 컴파일러, 인터프리터 등의 역할
관련 포스트: