템플릿 체화 드릴 _index
목적은 “C를 배우는 것”이 아니다. c코드 골격의 뼈대가 생각하지 않아도 손에서 나오게 만드는 것. 그래서 이 폴더의 드릴은 전부 같은 세 가지로 이루어진다. ① 요구사항서 → ② pseudo code 템플릿(보고 쳐서 익힌다) → ③ 테스트 코드(통과하면 끝).
이 폴더와 옆 폴더(실습/)의 차이
| 실습 가이드 (기존) | 템플릿 체화 드릴 (이 폴더) | |
|---|---|---|
| 출발점 | 개념 노트 (엔디안, atomic, epoll…) | 요구사항 한 장 (규격서 흉내) |
| 목표 | 그 개념이 동작하는 걸 본다 | 매번 같은 뼈대로 친다 |
| 성공 기준 | 돌아간다 | 안 보고 10분 안에 뼈대가 나온다 |
| 반복 | 1회 | 3회차 × 변형 3종 |
둘은 대체 관계가 아니다.
개념이 흔들리면 실습/, 손이 안 움직이면 여기.
드릴 노트의 공통 구성 (D0 ~ D9)
| 순서 | 내용 | 하는 일 |
|---|---|---|
| ① | 요구사항서 | 함수·구조체·에러 코드를 표로 확정한다. 변형 A / B / C 가 각각 있다 |
| ② | pseudo code 템플릿 | 빈칸([ ])이 있는 주석 뼈대. 1회차는 전부, 2회차는 번호와 제목만, 3회차는 백지 |
| ③ | 테스트 코드 | 정상 / 경계 / NULL / 실패 경로. 이게 PASS 면 끝이다. 빌드는 Makefile(gcc), 순수 gcc 명령은 접힌 참고 |
| ④ | 자주 하는 실수 | 흔히 밟는 지뢰와 그 증상 |
| ⑤ | 모범답안 | 맨 뒤에 접어 둔다 (D0 은 기준 헤더 링크, D9 은 회고) |
D6 은 코드를 치는 드릴이 아니다
mermaid 가 “코드”,
check.sh가 “테스트”다. D7 · D9 는 C 단위 시험에 셸 / python 시나리오 시험이 더해진다.
드릴 목록
| # | 드릴 | 쓰는 템플릿 | 목표 시간(3회차) | 한 줄 |
|---|---|---|---|---|
| D0 | 워밍업 — 뼈대 타자 연습 | 1 | 8분 | common.h / log.h / safe.h / guard.h 를 백지에서 친다 |
| D1 | 자원 없는 함수 | 1 | 12분 | 가드 → memset(out) → 로직 → RET_OK |
| D2 | 표 3장 → 구조체 | 2 | 22분 | has_/조건부(C), tagged union, 정렬·패딩 |
| D3 | 자원 잡는 함수 | 1 | 20분 | ret=RET_FAIL 시작, 역순 해제, 소유권 |
| D4 | Pack / Unpack | 3 | 25분 (확장 40분) | 커서 전진, 공간검사, 왕복 일치, Ver 조건·type 태그 union |
| D5 | TLV 파서 | 3 | 25분 (확장 38분) | 길이 신뢰 금지, unknown skip, 조건부 필수·IE union |
| D6 | 설계 산출물 | 5 | 15분 (확장 20분) | 코드 치기 전에 그림 4장, C·union ERD 표기 |
| D7 | 데몬 골격 | 4 | 40분 | 깃발만 드는 핸들러, 계단식 cleanup |
| D8 | 3GPP 한 조각 | 6 | 45분 | IE 표 5칸, M/C/O, oneOf/anyOf, 모르는 필드 보존 |
| D9 | 종합 | 1~6 | 120분 | 위 전부를 한 번에 |
순서를 건너뛰지 말 것
D4 를 못 치면 D8 에서 반드시 막힌다. D1~D3 이 전체의 70% 다.
반복 학습 방법 — 3회차 규칙
같은 드릴을 세 번 친다. 회차마다 보는 것이 줄어든다.
| 회차 | 볼 수 있는 것 | 하는 일 | 합격선 |
|---|---|---|---|
| 1회차 (모방) | 요구사항서 + pseudo code 전체 | pseudo 를 한 줄씩 코드로 바꾼다 | 테스트 PASS |
| 2회차 (재구성) | 요구사항서 + pseudo code 의 번호와 제목만 | 뼈대를 기억해서 친다. 막히면 그때만 연다 | 연 횟수 3회 이하 + 테스트 PASS |
| 3회차 (재현) | 아무것도 안 봄 | 백지에서 끝까지 | 목표 시간 안 + 테스트 PASS (경고 0, 새니타이저 0) |
그리고 회차마다 요구사항을 바꾼다. 각 드릴 노트에 변형 A / B / C 가 들어있다. 같은 문제를 세 번 치면 답을 외운 것이지 뼈대를 익힌 게 아니다.
간격 — 언제 다시 치나
D+0 1회차(변형 A) → D+1 2회차(변형 B) → D+4 3회차(변형 C) → D+14 점검(랜덤 변형)D+14 점검에서 목표 시간을 넘기면 그 드릴은 2회차로 되돌린다.
하루 루틴 (30분)
[5분] 워밍업 D0 — 백지에 guard.h 치기. 매일 같은 것.
[20분] 오늘의 드릴 1개 — 요구사항 읽기 3분 / 표 3분 / 뼈대 2분 / 로직 나머지
[5분] 테스트를 돌려 PASS 확인 + 아래 진도표에 체크막힌 곳을 안 적으면 반복이 안 쌓인다
드릴의 진짜 산출물은 코드가 아니라 “어디서 막혔는지” 다. 막힌 지점은 한 줄로 메모해 두고, 다음 회차의 목표로 삼는다.
작업 폴더 만들기
노트는 이 폴더, 코드는 vault 밖에 둔다.
mkdir -p ~/cdrill/{d0_warmup,d1_pure,d2_model,d3_resource,d4_pack,d5_tlv,d7_daemon,d8_3gpp,d9}/{src,test}
mkdir -p ~/cdrill/d6_design ~/cdrill/common ~/cdrill/build공통 헤더 (한 번만 만들고 전 드릴에서 재사용)
~/cdrill/common/ 에 1번 템플릿의
common.h · log.h · safe.h · guard.h 를 놓는다.
단, D0 에서는 매번 백지에서 다시 친다.
(기준 헤더는 c-playgound/common/ 이고, mem.h · strx.h 는 필요해지는 드릴에서 가져온다. 매크로 정리는 종합본 참고.)
공통 Makefile
# ~/cdrill/Makefile
# 사용법: make D=d1_pure V=msisdn
# 파일이 여러 개일 때: make D=d4_pack V=msgx SRC="d4_pack/src/msg.c d4_pack/src/body.c d4_pack/test/test_msgx.c"
# 데몬(빌드만): make D=d7_daemon V=daemon SRC="$(ls d7_daemon/src/*.c)" build/d7_daemon_daemon
# 외부 라이브러리: make ... LDLIBS="-pthread -ljansson"
CC := gcc
CFLAGS := -Wall -Wextra -Werror -std=c11 -D_POSIX_C_SOURCE=200809L -g -DUNIT_TEST -Icommon -I$(D)/src
SAN := -fsanitize=address,undefined -fno-omit-frame-pointer
LDLIBS ?= -pthread
D ?= d1_pure
V ?= main
SRC ?= $(D)/src/$(V).c $(D)/test/test_$(V).c
BIN := build/$(D)_$(V)
all: run
build:
@mkdir -p build
$(BIN): build $(SRC)
$(CC) $(CFLAGS) $(SAN) $(SRC) $(LDLIBS) -o $(BIN)
run: $(BIN)
@echo "── run ──────────────────────────────"
@./$(BIN)
# 위생 검사: 경고 0 + 새니타이저 0 이어야 통과
check: $(BIN)
@./$(BIN) && echo "PASS" || (echo "FAIL"; exit 1)
clean:
rm -rf build
.PHONY: all run check clean build
-Werror를 빼지 말 것경고를 켜 두고 무시하는 습관이 제일 나쁘다. 경고 = 빌드 실패 로 만들어야 손이 바뀐다. 정적분석기를 따로 돌리기 전에,
-Wall -Wextra -Werror가 이미 절반을 잡아준다.-pedantic은 넣지 않았다. gcc 는LOG_INF("hello")처럼 가변 인자가 0개인 호출을-pedantic에서 경고로 보고,-Werror와 만나 빌드가 깨진다.
합격 기준 (공통)
각 드릴의 합격 기준은 테스트가 PASS 인 것이다.
| 항목 | 기준 |
|---|---|
| 테스트 | 마지막 줄이 PASS (D6 은 check.sh 의 PASS) |
| 빌드 위생 | 경고 0, 새니타이저(ASan / UBSan / LeakSanitizer) 리포트 0 |
| 시간 | 목표 시간 이내 (목표의 2배를 넘으면 그 회차는 다시 한다) |
| 뼈대 | 가드로 시작하고 memset(out) 을 하며, 자원을 잡았다면 goto CLEANUP 단일 출구 |
테스트가 PASS 가 아니면 그 회차는 통과가 아니다. 같은 회차를 다시 한다.
전체 진도표
| 드릴 | 1회차 (A) | 2회차 (B) | 3회차 (C) | D+14 점검 |
|---|---|---|---|---|
| D0 | ☐ | ☐ | ☐ | ☐ |
| D1 | ☐ | ☐ | ☐ | ☐ |
| D2 | ☐ | ☐ | ☐ | ☐ |
| D3 | ☐ | ☐ | ☐ | ☐ |
| D4 | ☐ | ☐ | ☐ | ☐ |
| D5 | ☐ | ☐ | ☐ | ☐ |
| D6 | ☐ | ☐ | ☐ | ☐ |
| D7 | ☐ | ☐ | ☐ | ☐ |
| D8 | ☐ | ☐ | ☐ | ☐ |
| D9 | ☐ | ☐ | ☐ | ☐ |
관련 노트
- c코드 골격 목록 — 드릴이 체화시키려는 대상
- C언어 시스템 프로그래밍 단계별 실습 가이드 — 개념 기반 실습
- C언어 목록 — 상위 허브