C23 Double Bracket Attribute Syntax Guide
The C23 standard officially adopted the double bracket attribute
syntax, [[attribute]], directly aligning ISO C with modern
C++ standards. This article covers the origins of this syntax, the
problems it solves regarding compiler portability, the standard
attributes introduced in C23, and how developers can utilize them to
write cleaner, safer code.
Historically, C compilers relied on vendor-specific extensions to
provide metadata about functions, variables, and types. GCC and Clang
used __attribute__((...)), while Microsoft Visual C++ used
__declspec(...). This fragmented ecosystem led to
convoluted macro definitions across codebases to maintain cross-platform
compatibility. To resolve this fragmentation, the C Standards Committee
integrated the standardized double-bracket attribute syntax first
introduced in C++11.
In C23, attributes are enclosed within double square brackets, such
as [[nodiscard]] or [[deprecated]]. They can
be applied to various code entities, including functions, variables,
types, and statement blocks. Syntactically, they can appear with or
without arguments and can also support vendor-specific namespaces (for
example, [[gnu::always_inline]]) without breaking
conformance on other standard-compliant compilers, which are required to
ignore unrecognized attributes.
C23 specifies several standard attributes adopted directly from C++:
[[nodiscard]]: Signals a warning if the return value of a function call is discarded. An optional string literal can be provided to explain why the result must not be ignored (e.g.,[[nodiscard("Resource leak")]]).[[maybe_unused]]: Suppresses compiler warnings when a variable, function, or parameter is intentionally left unused.[[deprecated]]: Marks an entity as obsolete, optionally providing a message guiding the developer toward modern alternatives.[[fallthrough]]: Explicitly indicates that an intentional fallthrough occurs in aswitchstatement, silencing warnings from static analysis tools and compilers.
In addition to these common attributes, C23 introduced memory- and effect-tracking attributes tailored for C:
[[reproducible]]: Indicates that a function does not modify any observable state and returns the same output given the same arguments within a given execution sub-sequence.[[unsequenced]]: Signifies a pure, stateless function with no side effects and no dependencies on mutable global state, enabling aggressive compiler optimizations.
By adopting the [[...]] syntax, C23 establishes a
unified, cross-language mechanism for supplying semantic metadata,
reducing reliance on preprocessor hacks and improving interoperability
between modern C and C++.