처리중입니다. 잠시만 기다려주세요.
TTJ 코딩클래스
정규반 단과 자료실 테크 뉴스 코딩 퀴즈
테크 뉴스
Hacker News 2026.05.21 82

"C 코드는 거의 다 미정의 동작이다" - 30년차 개발자의 도발적 주장

Hacker News 원문 보기

제목부터 자극적인 글

이번에 화제가 된 글의 제목이 "Everything in C is undefined behavior"예요. 직역하면 "C 코드는 전부 미정의 동작이다" 인데, 좀 과장된 표현이긴 하지만 그만큼 C 언어를 진지하게 다뤄본 사람이라면 누구나 한 번쯤 했을 법한 푸념이기도 합니다. 작성자는 오랫동안 시스템 프로그래밍을 해온 개발자고, 글의 요지는 "우리가 별 생각 없이 짠 C 코드의 상당 부분이 사실 C 표준에 따르면 미정의 동작(undefined behavior, UB) 에 해당한다"는 거예요.

미정의 동작이 뭐냐면

주니어 분들을 위해 짧게 설명하면, 미정의 동작은 "C 언어 표준이 \"이 경우엔 컴파일러가 뭘 해도 정당하다\"고 명시적으로 손 놓은 영역"입니다. 흔히 알려진 예가 부호 있는 정수(signed integer)의 오버플로우예요. int x = INT_MAX; x + 1; 같은 코드를 쓰면 많은 사람은 "음수로 휙 뒤집히겠지" 생각하지만, C 표준 입장에선 "몰라요, 컴파일러 마음이에요"입니다. 컴파일러는 이걸 근거로 "이 변수는 절대 오버플로우될 일이 없다" 고 가정하고 최적화를 할 수 있어요. 그래서 디버그 빌드에선 잘 돌던 코드가 릴리스 빌드에선 무한 루프가 되거나, if (x + 1 < x) 같은 검사가 통째로 사라져버리는 일이 생깁니다.

다른 흔한 UB 후보들은 이런 게 있어요. 널 포인터 역참조, 해제된 메모리 접근, 배열 범위 초과, 같은 객체를 두 시퀀스 포인트 사이에 두 번 수정하기(i = i++;), 정렬되지 않은 메모리에서 정수 읽기, 부호 있는 정수의 좌측 시프트… 이런 게 한두 개가 아니라 수백 개 단위로 존재합니다.

글의 진짜 논점

저자가 강조하는 건 단순히 "UB가 많다"가 아니에요. 진짜 무서운 건 현대 컴파일러의 최적화기가 이런 UB를 "있을 수 없는 일"로 가정하면서 코드의 의미를 적극적으로 바꿔버린다는 점이거든요. 1990년대 GCC는 비교적 "순진하게" 사람이 쓴 코드를 그대로 기계어로 옮겼는데, 2020년대 GCC와 Clang은 "UB라면 절대 일어나지 않는다고 믿고" 코드를 통째로 들어내거나 재배치합니다.

예를 들어 보안 코드에서 자주 보이는 패턴이 있어요. "민감한 데이터를 쓰고 난 뒤 memset으로 0을 채워서 메모리를 지운다." 그런데 이 변수가 그 이후로 안 읽힌다면, 컴파일러는 "안 읽힐 메모리에 0을 쓰는 건 의미 없는 작업"이라고 판단해서 memset 호출 자체를 통째로 삭제해버릴 수 있습니다. 보안적으로는 치명적이지만 표준상으론 합법이에요. 그래서 memset_s 같은 별도 함수가 나오게 된 거고요.

또 하나 유명한 사례가 리눅스 커널의 NULL 체크 버그예요. 포인터를 한 번 역참조한 다음에 NULL 체크를 했더니, 컴파일러가 "이미 역참조했으니 NULL일 리 없다"고 판단해서 NULL 체크 자체를 삭제해버린 사건이 있었습니다. 권한 상승 취약점으로 이어졌죠.

그래서 C를 버려야 할까

이 지점에서 자연스럽게 따라오는 흐름이 Rust, Zig, Carbon 같은 새 시스템 언어들이에요. Rust는 안전하지 않은 메모리 접근을 컴파일 타임에 차단하고, Zig는 "UB를 명시적으로만 허용"하는 방향이고, Carbon은 "C++와 상호운용되면서 점진적으로 안전하게 마이그레이션"을 노립니다. 마이크로소프트와 구글이 자사 코드베이스의 메모리 안전성 버그 중 약 70%가 C/C++ 출신이라고 발표한 이후 이 흐름은 사실상 업계 합의가 됐어요.

그렇다고 C가 곧 사라지진 않습니다. 리눅스 커널, glibc, OpenSSL, SQLite 같은 우리가 매일 의존하는 소프트웨어가 다 C로 짜여 있고, 임베디드와 펌웨어 세계에선 여전히 압도적이에요. 현실적 답은 "C를 계속 쓰되 UB를 줄이는 도구를 적극 활용하라" 입니다.

한국 개발자에게 주는 시사점

실무에서 당장 챙길 만한 건 이래요. UBSan(UndefinedBehaviorSanitizer)과 ASan(AddressSanitizer)을 빌드 파이프라인에 넣어두세요. -Wall -Wextra -Wpedantic 같은 경고 옵션은 기본이고, -fno-strict-aliasing처럼 위험한 최적화를 의도적으로 꺼두는 것도 임베디드에선 흔한 선택입니다. 그리고 새 프로젝트라면 Rust를 진지하게 고민할 시점이에요. 리눅스 커널에도 Rust가 들어가는 시대니까요.

핵심 한 줄은 이거예요. "C는 우리가 생각하는 만큼 우리에게 친절하지 않다." 여러분이 마지막으로 만난 UB 버그는 어떤 거였나요? 혹시 "이상하게 디버그 빌드에선 되는데 릴리스에선 안 되는" 그런 경험, 있으셨다면 댓글로 공유해주세요.


🔗 출처: Hacker News

이 뉴스가 유용했나요?

TTJ 코딩클래스 정규반

월급 외 수입,
코딩으로 만들 수 있습니다

17가지 수익 모델을 직접 실습하고, 1,300만원 상당의 자동화 도구와 소스코드를 받아가세요.

144+실전 강의
17개수익 모델
4.9수강생 평점
정규반 자세히 보기

"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"

실제 수강생 후기
  • 비전공자도 6개월이면 첫 수익
  • 20년 경력 개발자 직강
  • 자동화 프로그램 + 소스코드 제공

매일 AI·개발 뉴스를 받아보세요

주요 테크 뉴스를 매일 아침 이메일로 전해드립니다.

스팸 없이, 언제든 구독 취소 가능합니다.