TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 30 READS

표준 C와 현실의 C는 다르다 — GCC·Clang·musl이 비켜가는 지점들

C로 코드를 짜는 개발자 대부분은 자신이 'C 표준에 맞는 코드'를 쓴다고 믿는다. 그러나 표준 문서가 규정한 C와, GCC·Clang 컴파일러 위에서 glibc나 musl 같은 표준 라이브러리와 함께 실제로 돌아가는 C 사이에는 적지 않은 간극이 있다. 한 개발자가 정리한 비공식 '비호환 목록'은 그 간극이 흔히 생각하는 사소한 버그 수준이 아니라, 기본 설정과 수십 년 묵은 미구현, 라이브러리 간 충돌에서 비롯된 구조적인 문제임을 보여준다. 임베디드나 수치 연산, 크로스 플랫폼 빌드를 다루는 실무자라면 한 번쯤 짚어둘 만한 지점들이다.

기본 설정부터 표준이 아니다

가장 먼저 눈에 띄는 것은 컴파일러가 기본 설정에서조차 표준을 완전히 따르지 않는다는 사실이다. GCC와 Clang은 기본적으로 asm을 확장 키워드로 인식한다. 하지만 표준 C에서 asm은 예약어가 아니라 그냥 쓸 수 있는 평범한 식별자다. 따라서 asm을 변수나 함수 이름으로 쓴, 엄밀히 표준에 맞는 코드가 두 컴파일러의 기본 설정에서는 컴파일되지 않을 수 있다. 물론 -std 옵션이 존재하는 이유가 바로 이것이고 그것으로 해결되지만, 컴파일러가 기본값에서 비표준이라는 점, 그리고 C++는 asm을 예약어로 지정해 둔 반면 C 표준은 왜 그러지 않았는지는 여전히 의문으로 남는다.

부동소수점 쪽에서는 더 분명한 위반이 드러난다. float.h의 FLT_ROUNDS 매크로는 표준상 현재 반올림 모드를 반영해야 하며, fenv.h의 fesetround 함수로 실행 중에 모드를 바꾸면 그 값도 함께 동적으로 변해야 한다고 명시돼 있다. 그런데 GCC는 런타임 반올림 모드와 무관하게 FLT_ROUNDS를 항상 1(가장 가까운 값으로 반올림)로 정의한다. Clang은 이를 처리하는 내장 함수 __builtin_flt_rounds()를 제공하지만, GCC에는 그런 대응물이 없다. 반올림 모드를 바꿔가며 수치 계산을 하는 코드라면, 이 매크로의 값을 신뢰할 수 없다는 뜻이다.

27년째 방치된 부동소수점 프래그마

부동소수점 연산 동작을 제어하기 위해 C 표준은 다섯 개의 표준 프래그마를 규정하고 있다. 문제는 C99가 표준화된 지 27년이 지난 지금까지도 GCC가 이 표준 프래그마를 하나도 지원하지 않는다는 점이다. GCC에서 이들은 그저 아무 동작도 하지 않는 no-op으로 처리된다. 일부 기능은 명령줄 플래그로 흉내 낼 수 있지만, 플래그는 번역 단위(translation unit) 전체에 적용되는 반면 프래그마는 개별 함수나 블록 단위로 적용할 수 있다는 결정적 차이가 있다. 세밀한 제어가 필요한 상황에서는 플래그가 프래그마를 대신하지 못한다. Clang은 C99 프래그마를 대체로 지원하지만, C23에서 추가된 프래그마는 아직 지원하지 않는다.

라이브러리와 컴파일러의 충돌

타입 한정자(qualifier)와 관련된 Clang의 동작도 표준과 어긋난다. 표준은 함수 반환 타입에 붙은 한정자가 버려지도록 요구한다. 즉 한정자가 붙은 반환 타입과 붙지 않은 반환 타입의 두 선언은 동일하게 취급돼야 하는데, Clang은 이 둘을 서로 호환되지 않는 선언으로 판단한다.

마지막 사례는 컴파일러가 아니라 표준 라이브러리 쪽에서 발생한다. musl은 컴파일러가 이미 자체적으로 제공하는 일부 헤더를 중복해서 제공하는데, 그중 하나가 stdarg.h다. 이 헤더는 freestanding 구현에서도 지원이 요구되는, 사실상 모든 컴파일러가 내장으로 갖추고 있는 헤더다. 그럼에도 musl이 자체 버전을 제공하기 때문에, 컴파일러는 내장 헤더 대신 musl의 것을 사용하게 된다. 문제는 musl의 헤더가 내장 헤더보다 열등하다는 데 있다. musl의 va_start 정의는 두 번째 인자를 생략할 수 있도록 허용한 C23 규정을 반영하지 못하고 있다. 그 결과 musl을 대상으로 컴파일할 때는, 컴파일러 자체가 C23의 단일 인자 va_start를 지원하더라도 그 기능을 쓸 수 없게 된다.

실무자가 얻을 교훈

이 목록이 전하는 메시지는 '컴파일러를 믿지 말라'는 식의 냉소가 아니다. 오히려 표준 준수는 기본값이 아니라 의식적인 선택의 결과라는 점을 상기시킨다. -std 옵션을 명시하지 않으면 확장 기능이 섞인 방언으로 컴파일되고, FLT_ROUNDS나 부동소수점 프래그마처럼 표준이 요구하는 동작도 실제로는 보장되지 않을 수 있다. 특히 반올림 모드에 민감한 수치 코드, musl 기반의 경량 컨테이너나 임베디드 빌드, 여러 컴파일러를 넘나드는 프로젝트에서는 이런 간극이 조용히 결과를 바꿔놓을 수 있다. 자신이 쓰는 도구 조합이 표준의 어느 지점에서 어긋나는지 미리 파악해 두는 것은, 이식성을 전제로 한 코드일수록 더 중요한 방어선이 된다. 다만 이 정리는 작성자 스스로 밝혔듯 완전한 목록이 아니라 일부 사례의 모음이며, 부동소수점 관련 항목들은 추후 별도의 글로 더 자세히 다뤄질 예정이라는 점도 함께 염두에 둘 만하다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://sebsite.pw/w/20261012-notstdc.html
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...