gcc, clang and musl depart from standard C, a blog post lists
A blog post titled "Your C is not standard C" offers what its author calls an incomplete list of incompatibilities between C as written in the standard and C as it exists for people who use gcc or clang with glibc or musl. It names five items.
First, the asm keyword. By default, gcc and clang recognize asm as a keyword extension. In standard C, asm is a valid non-reserved identifier, so code that conforms to the standard may not compile with default compiler settings. The author notes that the -std option exists for this reason, but finds it notable that compilers are not conformant by default, and asks why the standard does not simply make asm a reserved word, as C++ does. The author says they are not sure why C does not.
Second, FLT_ROUNDS. The standard specifies the macro in float.h and requires its value to change dynamically with the runtime floating environment. gcc always defines FLT_ROUNDS to 1 (rounds to nearest), regardless of the runtime rounding mode. The post quotes a comment from gcc's own header saying the macro is supposed to change with calls to fesetround. clang defines a builtin for this, __builtin_flt_rounds(), but gcc does not.
Third, the standard pragmas. The C standard specifies five pragmas that control floating point behavior: three added in C99 (including FENV_ACCESS and CX_LIMITED_RANGE, each taking ON, OFF or DEFAULT) and two added in C23 (FENV_ROUND and FENV_DEC_ROUND). Over 27 years after C99 was standardized, gcc still does not support any of them; they are no-ops. Some but not all of the functionality can be replicated with command-line flags, but those operate on the whole translation unit, whereas pragmas can apply to individual functions and blocks. clang mostly supports the C99 pragmas but not the C23 ones. The author says a dedicated post on the subject may come later.
Fourth, qualifiers in function return types. The standard requires them to be discarded, so int f(); and const int f(); should be identical declarations. clang treats the qualifiers as significant and reports "conflicting types for 'f'", with 1 error generated.
Fifth, an outdated va_start on musl. musl ships its own versions of some headers the compiler already provides, including stdarg.h, so compilers use musl's header instead of the builtin one. The author calls musl's header strictly worse. It defines va_start(v,l) as __builtin_va_start(v,l), which is incorrect because C23 allows the second argument to be omitted. The author's proposed fix is to define va_start as __builtin_c23_va_start(VA_ARGS) when STDC_VERSION is at least 202311L, and to keep the old definition otherwise. As it stands, when compiling for musl, C23's single-argument va_start cannot be used even if the compiler supports it.
The post closes with links to related notes: how glibc and musl handle math errors (math_errhandling), the lack of a portable way to check for string-to-float conversion errors in standard C, gcc and clang not storing language linkage information with function types in C++, and an inaccurate Linux man page.
Key facts
- By default gcc and clang treat asm as a keyword extension, although in standard C it is a valid non-reserved identifier.
- gcc always defines FLT_ROUNDS to 1 (rounds to nearest) even though the standard requires it to follow the runtime rounding mode; clang has __builtin_flt_rounds(), gcc does not.
- Over 27 years after C99, gcc supports none of the five standard floating point pragmas, which are no-ops there; clang mostly supports the C99 ones but not the C23 ones.
- clang rejects int f(); followed by const int f(); as conflicting types, though the standard says return type qualifiers are discarded.
- musl's own stdarg.h defines va_start with two arguments, which blocks C23's single-argument va_start when compiling for musl.
Why it matters
Many programmers assume that code written to the C standard will behave as the standard says on gcc and clang. The post shows five places where that assumption fails, some of them old: gcc has ignored the standard floating point pragmas for over 27 years after C99. The gaps affect floating point control, declarations and variadic functions, not just obscure corners of the language.
Who it affects
People who write portable or standards-conforming C, especially code that depends on floating point rounding behavior, on the standard pragmas, on using asm as an identifier, or on C23 features such as single-argument va_start. Anyone building for musl is hit by the va_start issue. Users of gcc and clang are the ones whose defaults the post describes.
How to use it
Read it as a checklist of things to test. The author points to the -std option as the way to get conformance for asm. For the pragmas, some of the functionality can be replicated with command-line flags, though those apply to the whole translation unit rather than to individual functions and blocks. For musl, the post gives the corrected va_start definition guarded by STDC_VERSION >= 202311L.
How solid is it
The claims are concrete and checkable: the post includes a compiler error transcript, a quoted line from gcc's header, and the exact definitions of va_start. All of it is the author's own account and analysis. The author is not named in the text, and the author calls the list incomplete.
Risks and caveats
No publication date and no compiler or library versions tested are given, so the behavior reported may differ on other releases. No response from gcc, clang or musl maintainers is reported. No glibc-specific incompatibility is described, although glibc appears in the intro. The pragma section is explicitly a short version, with a longer post promised and no timeline given.
“the two declarations should be identical, but clang thinks they're incompatible.”
— the post's author, "Your C is not standard C"