C (C23)

This assessment applies the coupling account — coupling as access to a shared resource, and the coupling floor [1], [2] — and the knowledge-embodiment theorem [3]; the language is assessed against its official reference [4].

1 Assessment

This page assesses C in five parts: core coupling — what the language’s own constructs force; ecosystem coupling — what the surrounding platform, tooling, and community cost; engineering readiness — whether the artifact can be reproduced, verified, observed, worked in quickly, connected to other languages, and governed openly; the profile — the unscored facts a score cannot express; and the scoring detail — the mechanism marks and the arithmetic behind every score. A ✅ bullet marks a construct that helps. A ⚠️ or ❌ bullet marks a cost; the scoring model does not price every cost named here.

Core coupling 25/100 · Ecosystem coupling 73/100 · Engineering readiness 65/100

1.1 Core coupling

1.1.1 Type

  • ✅ Structs separate data: Pure data, no methods
  • ✅ Function pointers enable polymorphism: Can pass behavior as data
  • ❌ No encapsulation: Everything is public
  • ❌ No generics: Void pointers couple to type casting
  • ✅ No inheritance: Can’t create coupled hierarchies
  • ❌ Header files couple: Includes create compilation dependencies
  • ❌ Macros couple: Preprocessor doesn’t respect scope
  • ❌ No namespaces: Global namespace pollution

1.1.2 Construction

  • ✅ Explicit memory management: Allocation separate from initialization
  • ✅ Designated initializers: Can initialize specific fields
  • ❌ No constructors: Manual initialization couples to usage
  • ❌ Global state common: Static variables couple modules

1.1.3 Memory

  • ✅ Manual control enables precise memory strategy: Can separate memory management from logic
  • ✅ Explicit allocation/deallocation: malloc/free make lifetime visible
  • ❌ No safety: Use-after-free, double-free, memory leaks all possible
  • ❌ No RAII: Must manually track and free resources
  • ✅ Predictable: No GC pauses, deterministic performance
  • ❌ Pointer arithmetic couples to memory layout: Buffer overruns couple to hardware, with no abstraction over memory
  • ✅ Custom allocators: Can decouple allocation strategy (arena, pool, etc.)
  • ❌ Undefined behavior on errors: Buffer overruns, null derefs, and other memory-safety violations are UB

1.1.4 Error

  • ✅ Explicit error codes: Return values make errors visible
  • ❌ No enforcement: Can ignore return values
  • ❌ errno couples: Global error state couples functions
  • ❌ NULL everywhere: Pointer errors couple all code

1.1.5 Concurrency

  • ❌ pthreads manual: All synchronization explicit
  • ❌ Shared mutable state default: No protection
  • ❌ Data races are undefined behavior: No prevention
  • ⚠️ Explicit is predictable: At least coupling is visible

1.1.6 Platform

  • ✅ No platform owner: The language is standardised by ISO/IEC and implemented independently by GCC, Clang, and MSVC, so no single vendor controls it
  • ✅ No required platform runtime: A conforming program depends only on the C standard library, not on a vendor runtime
  • ✅ Every mainstream platform has a C compiler: Linux, macOS, Windows, and embedded targets all have conforming implementations, and operating systems expose a C ABI to other languages
  • ✅ No single-implementation dependence: Source compiles under more than one compiler, so the loss of one implementation does not strand the code

1.1.7 Trade-offs (not coupling)

  • Power vs. Safety: Complete control couples to complete responsibility for safety
  • Simplicity vs. Safety: No abstractions means manual discipline required to control coupling
  • Performance vs. Correctness: Optimization couples to unsafe patterns (buffer tricks, pointer arithmetic)
  • Portability vs. Platform Access: Platform-specific code couples to hardware/OS
  • Manual Memory Management: Must couple resource acquisition to every usage site
  • Undefined Behavior Everywhere: Memory errors couple entire program to runtime environment
  • Header Dependencies: Changes to one header couple to all files that include it (transitively)

1.2 Ecosystem coupling

1.2.1 Performance

  • ✅ Maximum performance: No abstraction overhead
  • ✅ No GC: Deterministic, predictable
  • ✅ Full control: Manual everything
  • ✅ Predictable: What you write is what runs
  • ✅ Minimal runtime: Runs anywhere

1.2.2 Ecosystem

  • ✅ Ubiquitous: Available on every platform
  • ⚠️ Build systems: Make, autotools, CMake fragmentation
  • ✅ Mature tooling: GCC, Clang, debuggers
  • ⚠️ No package manager: Manual dependency management
  • ✅ Stable ABI on a given platform: A platform’s C ABI is long-stable, so binaries built by ABI-compatible compilers interoperate on that platform (the C standard itself defines no ABI, and compatibility is not guaranteed across compilers or targets)

1.2.3 Evolution

  • ✅ Extremely stable: C89/C99/C11/C17/C23 all backward compatible
  • ✅ No breaking changes: Code from 1980s still compiles
  • ✅ Conservative: Changes are minimal
  • ⚠️ Slow evolution: New features take decades

1.2.4 Domain

  • ✅ Excellent for systems: OS kernels, drivers
  • ✅ Great for embedded: Minimal footprint
  • ✅ Strong for performance: No overhead
  • ✅ Good for portability: Runs everywhere
  • ⚠️ Not for application dev: Too low-level

1.2.5 Learning

  • ✅ Simple language: Small, learnable
  • ❌ Hard to master: Undefined behavior, pointers
  • ✅ Lots of resources: K&R, tutorials
  • ❌ Many footguns: Easy to shoot yourself

1.2.6 Syntax

  • ✅ Simple, direct: Minimal syntax
  • ❌ No abstractions: Manual everything
  • ❌ Pointer syntax: int *(*fp)(void) confusing
  • ✅ Explicit: Clear what’s happening

1.2.7 Testing

  • ⚠️ Testing frameworks: Check, Unity, cmocka
  • ✅ Excellent debuggers: Gdb, lldb
  • ❌ Manual memory tracking: Valgrind needed
  • ⚠️ UB makes debugging hard: Anything can happen

1.2.8 Security

  • ❌ Memory unsafe: All memory bugs possible
  • ❌ Buffer overflows: No bounds checking
  • ❌ Undefined behavior: Security vulnerabilities
  • ❌ No protection: Manual everything

1.3 Engineering readiness

1.3.1 Reproducibility

  • ❌ Builds are not byte-reproducible by default.
  • ❌ Dependencies resolve without a lock by default.

1.3.2 Supply chain

  • ⚠️ Published packages carry no signed provenance by default.

1.3.3 Observability

  • ⚠️ No stable tracing and metrics standard.
  • ⚠️ The standard library has no structured logging.

1.3.4 Feedback

  • ✅ No charged mechanism in this dimension.

1.3.5 Interop

  • ✅ No charged mechanism in this dimension.

1.3.6 Governance

  • ✅ No charged mechanism in this dimension.

1.4 Profile

Unscored, and kept separate from every score on purpose. The profile records what a mechanism price cannot express: what a running program costs, how well a coding model and an agent work in the language, and whether a safety-critical path exists.

1.4.1 Energy and cost

What this axis asks: what does a running program cost in energy and time?

  • ✅ Compiles to native code: the fastest class in the language energy and time benchmarks [5], [6]. A causal re-analysis attributes the difference to execution time [7].

1.4.2 AI and agent readiness

What this axis asks: how well does a coding model and an agent work in this language?

  • ✅ A large training corpus and strong code-generation results: models write this language well [8], [9].

1.4.3 Safety certification

What this axis asks: is there a certified or standards-qualified path to a safety-critical system?

  • ✅ A standards-qualified toolchain or an established safety standard covers this language.

1.5 Scoring detail

1.5.1 Core coupling Dimensions

Dimension Mechanism Description Present Cost
Type T1 dynamic no static check ✅ −15
T2 weak static ✅ −8
T3 dynamic/duck dispatch — 0
T4 no sum types — 0
T5 no generics ✅ −4
T6 no namespaces ✅ −8
T7 type erasure/reflection — 0
T8 operator overloading ✅ −4
T9 inheritance required for polymorphism ✅ −4
T10 no null-safety ✅ −8
T11 no module boundary ✅ −8
T12 no effect tracking ✅ −8
T13 async/sync colouring — 0
T14 unchecked foreign boundary ✅ −4
Type subtotal −15 (−71)
Construction C1 global mutable state by default ✅ −15
C2 no immutability by default ✅ −4
C3 constructors coupled to allocation ✅ −4
C4 no constructor/validation ✅ −4
Construction subtotal −15 (−27)
Memory M1 manual deallocation ✅ −15
M2 GC non-deterministic pauses — 0
M3 no RAII ✅ −4
M4 no ownership model ✅ −8
Memory subtotal −15 (−27)
Error Er1 no structured path ✅ −15
Er2 unchecked exceptions only — 0
Er3 errors ignored/non-exhaustive ✅ −4
Er4 no composable result type ✅ −4
Error subtotal −15 (−23)
Concurrency K1 GIL/no parallel — 0
K2 shared mutable state default ✅ −8
K3 manual sync no race detection ✅ −8
K4 no structured concurrency ✅ −4
K5 no primitives — 0
Concurrency subtotal −15 (−20)
Platform P1 cannot function outside one vendor/domain — 0
P2 single-vendor but other uses — 0
P3 legacy/discontinued platform — 0
Platform subtotal 0

Core Dimensions score: 25/100 — total cost = −75 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).

1.5.2 Ecosystem coupling Dimensions

Dimension Mechanism Description Present Cost
Performance R1 interpreted no AOT/JIT — 0
R2 GC pauses — 0
R3 JIT warmup — 0
Performance subtotal 0
Ecosystem Ec1 no package manager ✅ −4
Ec2 fragmented tooling ✅ −8
Ec3 small/niche/discontinued — 0
Ec4 proprietary — 0
Ec5 platform-locked tooling — 0
Ec6 monoculture — 0
Ec7 legacy burden — 0
Ecosystem subtotal −12
Evolution V1 breaking changes — 0
V2 frozen — 0
V3 discontinued — 0
V4 glacial standards — 0
Evolution subtotal 0
Domain D1 domain/vendor lock-in — 0
D2 poor domain fit — 0
D3 framework forces architecture — 0
Domain subtotal 0
Learning L1 steep — 0
L2 large surface/multi-paradigm — 0
L3 sparse docs — 0
Learning subtotal 0
Syntax S1 verbose — 0
S2 inconsistent — 0
S3 punctuation-heavy — 0
Syntax subtotal 0
Testing G1 weak tooling — 0
G2 poor debugging — 0
G3 runtime-only errors — 0
Testing subtotal 0
Security Q1 memory-unsafe ✅ −15
Q2 dynamic/weak typing risk — 0
Q3 known vulnerability/injection — 0
Security subtotal −15

Meta Dimensions score: 73/100 — total cost = −27 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).

1.5.3 Engineering readiness Dimensions

Dimension Mechanism Description Present Cost
Reproducibility Y1 build not reproducible ✅ −8
Y2 dependencies not pinned ✅ −8
Reproducibility subtotal −15 (−16)
Supply chain Y3 no signed provenance ✅ −8
Y4 registry without namespacing — 0
Supply chain subtotal −8
Observability Y5 no stable tracing standard ✅ −8
Y6 no structured logging ✅ −4
Observability subtotal −12
Feedback Y7 slow build — 0
Y8 no fast in-editor analysis — 0
Feedback subtotal 0
Interop Y9 no foreign-function interface — 0
Y10 no portable target — 0
Interop subtotal 0
Governance Y11 single-vendor governance — 0
Y12 closed specification — 0
Governance subtotal 0

Readiness Dimensions score: 65/100 — total cost = −35 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).

Verdict: C provides no coupling prevention mechanisms but also imposes few forced coupling constructs — the language itself is neutral. With discipline, developers can separate concerns through function pointers, explicit error codes, and manual memory management. Without discipline, globals, macros, and undefined behavior couple everything. Main insight: coupling in C is entirely up to the programmer. The same language can produce extremely low or extremely high coupling depending on how it is used.


The formal development. The definitions, theorems, and proofs behind this page are published in:

All published papers

References

[1]
Y. Loth, “On the nature of coupling: All coupling as shared resource access.” Zenodo, Aug. 2026. doi: 10.5281/zenodo.21925122.
[2]
Y. Loth, “Coupling as a consequence of cohesion: Decomposition, the coupling floor, and domain-imposed coupling.” Zenodo, Aug. 2026. doi: 10.5281/zenodo.21925201.
[3]
Y. Loth, “On the nature of cohesion: Cohesion as correctness relative to a partitioning rule.” Zenodo, Jul. 2026. doi: 10.5281/zenodo.21703193.
[4]
ISO/IEC JTC 1/SC 22, “Information technology — programming languages — C.” International Organization for Standardization; International Standard ISO/IEC 9899:2024 (C23), Geneva, Switzerland, 2024.
[5]
R. Pereira et al., “Energy efficiency across programming languages: How do energy, time, and memory relate?” in Proceedings of the 10th ACM SIGPLAN international conference on software language engineering (SLE), 2017, pp. 256–267. doi: 10.1145/3136014.3136031.
[6]
R. Pereira et al., “Ranking programming languages by energy efficiency,” Science of Computer Programming, 2021, doi: 10.1016/j.scico.2021.102609.
[7]
N. van Kempen, H.-J. Kwon, D. T. Nguyen, and E. D. Berger, “It’s not easy being green: On the energy efficiency of programming languages,” in Proceedings of the 40th IEEE/ACM international conference on automated software engineering (ASE), 2025. doi: 10.1109/ASE63991.2025.00131.
[8]
S. Joel, J. J. Wu, and F. H. Fard, “A survey on LLM-based code generation for low-resource and domain-specific programming languages,” ACM Transactions on Software Engineering and Methodology, 2025, doi: 10.1145/3770084.
[9]
Y. Qing et al., “EffiBench-x: A multi-language benchmark for measuring efficiency of LLM-generated code,” in Advances in neural information processing systems 38 (NeurIPS), datasets and benchmarks track, 2025. doi: 10.48550/arXiv.2505.13004.