Fundamentals 20 min read

Why C Is No Longer Just a Language – It’s a Universal ABI Protocol

The article explains how C has evolved from a programming language into a universal ABI protocol that every language must speak to interact with operating systems, detailing the challenges of FFI, ABI compatibility, and strategies for forward‑compatible API design.

21CTO
21CTO
21CTO
Why C Is No Longer Just a Language – It’s a Universal ABI Protocol

Aria Beingessner’s provocative essay argues that C has been elevated to a role of absolute authority, becoming a universal protocol rather than merely a programming language.

Both Beingessner and his colleague Phantomderp share a deep frustration with the C ABI, noting that every useful program must ultimately interact with an OS written in C, forcing languages to use C’s foreign function interface (FFI) to call system APIs.

The piece emphasizes that C’s dominance forces languages like Rust, Swift, and even Python to wrap themselves in C‑compatible skins, effectively speaking C to interoperate.

External Function Interface

Using a hypothetical language Bappyscript, the article illustrates how any new language must provide an interface to the OS, typically via C’s open family of functions:

#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat2(int dirfd, const char *pathname, const struct open_how *how, size_t size);

Because C lacks a formal ABI, parsing its headers is notoriously difficult; tools like rust‑bindgen rely on a C compiler rather than pure syntax analysis.

Bindgen uses libclang to parse C/C++ headers, but true parsing requires handling #include , typedef , and macros, which is beyond pure syntactic analysis.

Swift is highlighted as an example of a language with strong FFI support, able to import C headers and generate native interfaces automatically.

ABI Compatibility and Target Triples

The article discusses how ABI differences across platforms are managed via target triples (e.g., x86_64-unknown-linux-gnu) and how symbol versioning allows libraries to evolve without breaking existing binaries.

Examples include versioned symbols such as my_rad_symbol_v1 and my_rad_symbol_v2, and the challenges when new versions cannot link against older libraries.

Designing Forward‑Compatible APIs

Reserve unused fields for future extensions.

Use opaque pointers and versioned type prefixes.

Employ size‑adaptive fields that older versions can skip.

Case studies such as Microsoft’s MINIDUMP_HANDLE_DATA_STREAM and the glibc jmp_buf illustrate how careful layout and symbol versioning preserve compatibility across architectures.

Ultimately, the author concludes that C has become a protocol that all languages must obey, and while it offers unparalleled portability, its design flaws make ABI stability a perpetual nightmare.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

FFIC languageabiInteroperabilitySystems Programmingtype compatibility
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.