현장에서 가장 많이 터지는 C 사고 패턴들
C언어C로 사고가 났다는 얘기를 들으면
원인은 매번 새로워 보이지만,
코드를 열어보면 장면은 거의 비슷하다.
놀라운 건
이 사고들이 대부분
“어려운 문제”에서 나오지 않는다는 점이다.
아주 사소해 보이는 선택들이
시간이 지나며 문제를 키운다.
1) 수명 관리가 보이지 않는 포인터
가장 흔한 패턴이다.
- 포인터는 살아 있는데
- 가리키는 대상은 이미 사라진 상태
이 상태의 코드는
당장 터지지 않는다.
그래서 더 위험하다.
테스트 환경에서는 멀쩡하다가
운영 중, 특정 타이밍에만
의미 없는 값이나 크래시로 돌아온다.
이 사고의 공통점은 하나다.
“이 포인터가 언제까지 유효한지
아무도 설명하지 못한다.”
2) 크기를 믿고 복사하는 코드
C 사고의 단골 손님이다.
- 문자열 길이를 믿고
- 배열 크기를 기억에 의존하고
- 입력이 설계대로 들어올 거라 기대한다
문제는
그 기대를 깨는 건
항상 외부라는 점이다.
파일, 네트워크, 사용자 입력.
이 중 하나만 흔들려도
버퍼는 바로 넘어간다.
이 패턴의 무서운 점은
“지금까지 문제 없었다”는 말이
아무 의미도 없다는 것이다.
3) 실패했는데도 계속 진행하는 흐름
많은 C 코드가
실패를 감지하지만
그걸 멈출 이유로 쓰지 않는다.
- malloc 실패
- 파일 오픈 실패
- 장비 응답 실패
에러 코드는 반환되는데
호출자는 그냥 다음 줄로 간다.
이 구조에서 사고는
즉시 터지지 않는다.
조금 더 진행한 뒤,
전혀 상관없는 지점에서 터진다.
그래서 디버깅은 더 어려워진다.
4) 계약이 없는 함수 인터페이스
현장에서 자주 보는 함수 시그니처다.
- 입력 범위가 불분명하고
- 반환값의 의미가 모호하고
- 실패 시 상태가 정의돼 있지 않다
이런 함수는
사용하는 쪽에서
항상 암묵적인 전제를 깔게 만든다.
그 전제가 하나라도 어긋나는 순간
사고는 자연스럽게 발생한다.
C에서 함수는
코드 조각이 아니라 계약이다.
이 계약이 문서나 시그니처로 드러나지 않으면
사고는 시간문제다.
5) 정리 순서를 고려하지 않은 종료 코드
사고는 시작보다
종료에서 더 많이 난다.
- 리소스 해제 순서
- 스레드 종료 타이밍
- 전역 객체 정리
종료 코드가
“어차피 끝나는 거니까”라는 이유로
대충 작성되면
희한한 버그가 생긴다.
특히
프로그램 종료 시점에만 터지는 버그는
재현도 어렵고, 로그도 부족하다.
6) 테스트가 아니라 운에 맡긴 코드
마지막 패턴은
사고라기보다 태도에 가깝다.
- 특정 입력만 테스트
- 정상 흐름만 확인
- 에러 경로는 직접 안 타봄
C는
운이 좋으면 오래 버틴다.
하지만 운은
언젠가 반드시 떨어진다.
테스트하지 않은 경로는
아직 사고가 안 났을 뿐,
안전한 게 아니다.
C 사고 패턴을 보면
공통점이 하나로 모인다.
- 책임이 보이지 않고
- 경계가 흐리고
- 실패를 가볍게 여긴다
이건 문법 문제가 아니다.
사고를 대하는 태도의 문제다.
다음 글에서는
이 사고 패턴들을
어떻게 코드 수준에서 차단할 수 있는지,
C를 조금 더 안전하게 쓰는 기준들을
정리해보려 한다.
도구가 아니라
습관의 이야기다.
'C언어' 카테고리의 다른 글
| C언어의 진짜 난이도는 문법이 아니라 '보이지 않는 규칙'에 있다 (0) | 2026.01.06 |
|---|---|
| 사고를 줄이는 C 코드의 기준과 습관 (1) | 2025.12.27 |
| C에서 아직도 사고 나는 이유는 문법이 아니다 (0) | 2025.12.25 |
| 📝 C 언어 함수 포인터와 콜백 함수: 유연한 코드 설계를 위한 핵심 패턴 (0) | 2025.11.21 |
| 이중 포인터로 2차원 배열 다루기 – 개념부터 실전 사용까지 (0) | 2025.11.20 |