C 표준과 실제 gcc·clang·musl 동작의 차이 정리
- gcc는 FLT_ROUNDS를 항상 1로 고정해서 런타임 반올림 모드 변경을 반영하지 않음
- 표준은 fesetround로 바뀐 반올림 모드를 FLT_ROUNDS가 반영하도록 요구하지만 gcc는 이를 무시함
- gcc는 C99 때 정의된 #pragma STDC 표준 pragma를 27년 넘게 지원하지 않아서 아무 동작 없는 no-op으로 처리됨
- clang은 int f(); 와 const int f(); 를 충돌 오류로 처리하지만 표준상 반환 타입 한정자는 버려지므로 두 선언은 같아야 함
Hacker News 의견들
Plan 9 C 쓰는 입장에서 보면 표준 C는 그냥 엉망이야. 컴파일러가 쓸 만한 게 두 개뿐이고 인라인 asm이 이식성을 망가뜨림. #ifdef 도배 말고 코드를 나눠서 관리하면 되는 거 아님?
atomic은 요즘 필수인데 post C99 추가 기능이 쓸모없다는 건 좀 과하지. C11 thread_local이랑 _Atomic은 진짜 잘 쓰고 있음.
gcc -fplan9-extensions 켜면 Plan 9 상속 쓸 수 있음. 태그 달린 enum이랑 void 포인터 배열로 다형성 워크플로 짜기 꽤 편함.
나는 fopen의 x 모드, aligned_alloc, CMPLX 매크로, [[foo]] 속성 문법이 좋더라. C23에서 _Bool 같은 밑줄 키워드 정리한 것도 다행임. _Generic은 템플릿 흉내 느낌이라 별로고.
char 부호가 구현 정의인 게 피해가 엄청남. D처럼 char를 unsigned로 못 박고 배열을 제대로 만들면 배열 오버플로 걱정이 확 줄어듦.
3년마다 스펙 바꾸는 건 표준이라고 부르기 좀 그렇지 않음?
Plan 9 저자들은 애초에 표준에 별로 신경 안 썼음. Rob Pike 스타일 헤더 구조랑 Plan 9 전용 관용구 섞인 C89에 가깝지.
리눅스도 Linus가 syscall ABI는 잘 지키는데 C를 어셈블리 소스로 빼서 컴파일러 의존을 줄였어야 했다고 봄. 그래야 cproc이나 qbe 같은 작은 컴파일러로 빌드할 수 있음.
Plan 9 좋아한다면서 앱이 거의 없는 건 왜임? 에디터도 두세 개밖에 없잖아. 그럼 무슨 소프트웨어 짜는데?
gcc가 FENV_ACCESS를 지원 안 하니까 fesetround 호출이 어차피 UB라서, 기본 반올림 모드로 고정돼 있어도 틀린 말은 아님. 그래도 지원 안 하는 건 문제긴 함.
gcc의 옛날 #pragma 부활절 달걀 생각난다. 1.21 전에는 #pragma 만나면 /usr/games/hack이나 rogue를 실행하려고 했음. 근데 그 인자로 #pragma 넘기는 건 무슨 의미였는지 모르겠음.