C extensions, portability, and alternative compilers
4 hours ago
- #C Programming
- #Portability
- #Compiler Development
- Real-world C code often relies on non-standard behaviors and compiler extensions, not just for features but to work around bugs and gaps in compilers and libraries.
- System C library headers (e.g., glibc's sys/cdefs.h) use preprocessor checks for compiler-specific macros, but these can be broken for non-GCC/clang compilers, affecting ABI compatibility.
- Compiler-builtin headers (e.g., stddef.h, limits.h) are required for freestanding implementations, but POSIX adds platform-specific constants, leading to complex header dependencies.
- Feature detection in projects like SDL_endian.h can be flawed, assuming GCC-style inline assembly for unknown compilers based on ISA macros, ignoring builtin availability.
- Inline function semantics (e.g., __only_inline in OpenBSD) are messy due to conflicts between C99, GCC pre-C99 behavior, and C++, requiring compiler-specific workarounds.
- Gnulib's compatibility code for extern inline highlights widespread broken implementations, with convoluted preprocessor logic to handle different compilers and versions.
- Bionic (Android's libc) heavily uses clang-specific extensions (e.g., _Nonnull), requiring command-line flags to define them away for other compilers.
- Compiler developers face challenges: patching upstream incompatibilities, gaining popularity for dedicated support, distributing patches, or pretending to be GCC to minimize disruption.
- Clang defines __GNUC__ to claim GCC 4.2.1 compatibility but avoids bumping version macros to prevent unchecked use of newer GCC extensions, advocating for feature test macros instead.
- The GCC/clang duopoly dominates *NIX land, but independent C compilers (tcc, cproc, etc.) persist, highlighting the difficulties of C portability and compiler compatibility.