템플릿 체화 드릴 _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워밍업 — 뼈대 타자 연습18분common.h / log.h / safe.h / guard.h 를 백지에서 친다
D1자원 없는 함수112분가드 → memset(out) → 로직 → RET_OK
D2표 3장 → 구조체222분has_/조건부(C), tagged union, 정렬·패딩
D3자원 잡는 함수120분ret=RET_FAIL 시작, 역순 해제, 소유권
D4Pack / Unpack325분 (확장 40분)커서 전진, 공간검사, 왕복 일치, Ver 조건·type 태그 union
D5TLV 파서325분 (확장 38분)길이 신뢰 금지, unknown skip, 조건부 필수·IE union
D6설계 산출물515분 (확장 20분)코드 치기 전에 그림 4장, C·union ERD 표기
D7데몬 골격440분깃발만 드는 핸들러, 계단식 cleanup
D83GPP 한 조각645분IE 표 5칸, M/C/O, oneOf/anyOf, 모르는 필드 보존
D9종합1~6120분위 전부를 한 번에

순서를 건너뛰지 말 것

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☐☐☐☐

관련 노트