핵심 요약
- 한 개발자가 GCC, Clang, glibc, musl 등 실제 널리 사용되는 C 개발 도구들이 공식 C 표준 규격과 일치하지 않는 다양한 불일치 사례들을 정리해 공개했다.
- asm 기본 예약어 충돌, 부동소수점 반올림 매크로(FLT_ROUNDS) 하드코딩, 27년 넘게 방치된 GCC의 C99 표준 프라그마 미지원 등 표준과 구현체 사이의 심각한 괴리가 구체적 코드로 제시됐다.
- POSIX 반환값 규격을 위반한 glibc의 initstate 오류 동작과 C23 단일 인자 va_start를 막아버리는 musl의 구식 헤더 문제 등 런타임 라이브러리 차원의 호환성 문제도 함께 지적됐다.
요약 데니스 리치의 명언을 인용하며 시작하는 이 글은 C 언어 공식 표준 문서에 적힌 내용과 GCC, Clang, glibc, musl 등 실제 개발 현장에서 널리 쓰이는 도구들 사이의 괴리를 구체적인 사례를 들어 짚어냅니다.
첫 번째로 기본 설정 문제를 지적합니다. GCC와 Clang은 기본적으로 'asm' 키워드를 확장 기능으로 인식하는데, 표준 C에서 'asm'은 예약어가 아닌 유효한 식별자입니다. 따라서 표준에 완벽히 부합하는 코드라도 컴파일러 기본 설정에서는 컴파일이 실패할 수 있습니다. C++처럼 표준에서 아예 예약어로 지정하지 않은 점도 의문으로 남습니다.
부동소수점 처리에서도 큰 차이가 드러납니다. float.h의 FLT_ROUNDS 매크로는 런타임에 fesetround 함수로 변경된 반올림 모드를 동적으로 반영해야 하지만, GCC는 이를 단순히 1(최근접 반올림)로 하드코딩해 두고 있습니다. Clang은 내장 함수를 통해 이를 지원하지만 GCC는 여전히 지원하지 않습니다. 또한 C99에서 도입된 부동소수점 표준 프라그마(#pragma STDC ...)들은 규격 제정 27년이 지난 지금까지도 GCC에서 아무런 동작도 하지 않는 무연산(no-op)으로 방치되어 있으며, Clang 역시 C23 신규 프라그마를 지원하지 못하고 있습니다.
라이브러리 및 문법 처리의 오류도 지적됩니다. glibc의 initstate 함수는 오류 발생 시 NULL을 반환해야 한다는 POSIX 규격을 어기고 NULL을 반환하지 않으며, man 페이지 버그 항목에만 슬그머니 기재되어 있습니다. Clang의 경우 함수 반환 타입의 한정자(const 등)는 버려져야 한다는 표준 규격이 있음에도 'int f();'와 'const int f();'를 타입 충돌 에러로 처리합니다. 아울러 경량 C 라이브러리인 musl은 자체 stdarg.h에서 va_start를 구식 2인자 매크로로 고정해 두어, C23 표준에서 허용된 1인자 va_start 기능을 무력화시키는 문제가 있습니다. 이처럼 개발자들이 매일 쓰는 C는 사실상 표준 C가 아니라는 점을 생생하게 보여줍니다.
Sponsored · 광고