C: Simple Defer, Ready to Use

A proposal to add a `defer`-style cleanup mechanism to C, inspired by Go and long emulated via GCC extensions and macros, is reigniting debate over how the language should handle resource management. Supporters argue that built-in defer or cleanup attributes would prevent common bugs around leaks and error paths, offering a safer alternative to manual gotos and ad‑hoc patterns used in large C codebases like the Linux kernel. Critics counter that such features obscure control flow, risk subtle ordering bugs, and further erode C’s supposed simplicity, suggesting that more feature-rich languages or explicit cleanup code remain preferable.

Role and Value of defer in C

  • Many see a standardized defer as long overdue for C, arguing it would prevent resource leaks and common cleanup bugs, especially for programmers used to C++ RAII.
  • Others say C does not “need” this; existing patterns (gotos, arrow pattern, explicit cleanup blocks) are sufficient and more explicit.
  • Some argue a mature language must grow to address real-world pain points; others fear feature bloat and want C to remain minimal and low-level.

Existing Mechanisms and Implementations

  • GCC’s __attribute__((cleanup)) already provides scope-exit cleanup; Apple’s libc and the Linux kernel use similar patterns.
  • The showcased macro implementation uses GCC nested functions; discussion clarifies:
    • Trampolines (and executable stacks) appear only when nested functions escape via pointers.
    • In the presented usage, no executable stack is needed and calls are optimizable.
  • Clang lacks GCC-style nested functions; alternate approaches include Blocks, cleanup attributes, or custom macros.
  • In C++, scope guards (e.g., Folly, Boost.Scope, homegrown ScopeGuard/lambda patterns) already provide defer-like behavior.

Goto, Structured Programming, and Readability

  • Several commenters defend goto for structured error handling and breaking out of nested loops, citing the Linux kernel as a positive example.
  • Others remain wary, viewing goto as a marker of messy code; alternatives like do { … } while (0) or one-iteration loops with break are used instead.
  • There’s an extended debate on Dijkstra’s critique:
    • One side claims modern goto is heavily “tamed” compared to what he attacked.
    • Another counters that C/C++ goto still breaks structured reasoning and can create irreducible control flow.

Visibility vs. Hidden Control Flow

  • Pro-defer camp: less boilerplate, fewer missed cleanups, clearer intent (“do X, and when leaving, do Y”).
  • Skeptics: defer (and C++ destructors) introduce invisible jumps and non-obvious execution order, especially with nested defers; they prefer explicit error paths with clearly ordered teardown.
  • Some suggest tooling that “desugars” defer to explicit gotos as a compromise between high-level clarity and low-level inspectability.

Exceptions and Unwinding Interactions

  • C standard does not define interaction with C++ exceptions; behavior is compiler- and flag-dependent.
  • GCC’s cleanup can participate in stack unwinding when -fexceptions is enabled, but this is non-default and not universal.
  • Consensus: interaction with exceptions is important in mixed C/C++ code but currently unclear for a standardized defer.