What Is New in C23? C Language Changes and Features
The C23 standard (ISO/IEC 9899:2024) marks the most significant update to the C programming language in over a decade, introducing modern syntax improvements, standardizing common idioms, and pruning outdated legacy constructs. This overview explores the finalized features of C23, covering fundamental language enhancements such as native booleans, type inference, standard attributes, and binary resource embedding, alongside critical library upgrades and deprecations.
Core Language Modernizations
- Native Booleans (
bool,true,false): Previously defined as macros in<stdbool.h>,bool,true, andfalseare now first-class keywords in the core language. The header<stdbool.h>remains available for backward compatibility. - Distinct Null Pointer (
nullptr): C23 introducesnullptrwith the underlying typenullptr_t. Unlike the traditionalNULLmacro (which often expands to(void*)0or integer0),nullptris explicitly a pointer type and cannot be inadvertently assigned to integer types. - Type Inference (
auto): Theautokeyword has been repurposed to deduce the type of a variable from its initializer, aligning with modern C++ usage. The variable must have an initializer to determine its type. - Type Queries (
typeofandtypeof_unqual): Long supported as a compiler extension (such as in GCC and Clang),typeofis now standard. It retrieves the type of an expression or type name.typeof_unqualfunctions similarly but stripsconst,volatile, andatomicqualifiers. - Empty Parameter Lists Mean "No Arguments": In prior
C standards, a function declared as
int foo()meant the function took an unspecified number of arguments. In C23,int foo()is strictly equivalent toint foo(void), taking zero arguments.
Syntax and Preprocessor Enhancements
- Binary Literals and Digit Separators: Programmers
can now write binary constants directly using prefixes like
0bor0B(e.g.,0b101010). Single quotes can be used as digit separators for improved readability in integer and floating-point literals (e.g.,1'000'000or0b1111'0000). - Standard Attribute Syntax (
[[...]]): C23 adopts the double-bracket attribute syntax introduced in C++11. Standardized attributes include:[[nodiscard]]: Warns if the return value of a function or type is ignored.[[maybe_unused]]: Suppresses compiler warnings for unused variables or parameters.[[deprecated]]: Warns when a designated entity is used, optionally accepting a reason string.[[fallthrough]]: Explicitly indicates an intentional fall-through in aswitchstatement.[[unsequenced]]and[[reproducible]]: Convey functional side-effect guarantees for compiler optimizations.
- Binary Resource Inclusion (
#embed): The#embedpreprocessor directive allows source files to directly incorporate raw binary data from external files into arrays as a sequence of integer values, eliminating the need for manual file-to-hex conversion scripts. - Conditional Directives (
#elifdefand#elifndef): These additions simplify preprocessor logic by replacing verbose combinations of#elif defined(...)and#elif !defined(...). - Flexible Label Placement: Labels can now be placed
at the end of compound statements or directly before declarations
without requiring an empty statement
(
{ label: int x = 0; }).
Data Types and Representations
- Mandatory Two's Complement: C23 drops historical support for one's complement and sign-magnitude representations. All signed integers are now guaranteed to use two's complement representation.
- Bit-Precise Integers (
_BitInt(N)): Introduces exact-width integer types where \(N\) defines the explicit number of bits (e.g.,_BitInt(24)orunsigned _BitInt(48)), useful for hardware modeling and FPGA target support. - Zero-Size Structures: Empty structure declarations
(
struct S {};) are now conditionally permitted with implementation-defined sizes.
Standard Library Additions and Hardening
- Checked Integer Arithmetic
(
<stdckdint.h>): Provides functions to perform safe additions, subtractions, and multiplications (ckd_add,ckd_sub,ckd_mul) that return a boolean indicating whether an overflow occurred. - Explicit Memory Zeroing
(
memset_explicit): Introduced in<string.h>to securely overwrite sensitive data (like passwords or cryptographic keys). Unlike standardmemset, compilers are prohibited from optimizing away this call. - POSIX Extensions in Standard C: Several widely used
POSIX utilities are now standardized in the C library, including
memccpy,strdup, andstrndup. - Time Improvements: Additions to
<time.h>includetimespec_getresfor querying time resolution and standardized handling of leap seconds.
Removed and Deprecated Features
- Removal of K&R Function Declarations: The ancient K&R declaration style (where parameters are listed in the signature and typed on subsequent lines) has been entirely removed from the language.
- Removal of Trigraghs: Three-character escape
sequences like
??=(for#) or??/(for\) have been completely removed. - Removal of
__alignof_is_definedand__alignas_is_defined: Replaced by core keyword alignments. - Deprecation of Static Asserts via Macro: The
static_assertkeyword is now directly part of the grammar and no longer requires<assert.h>, also permitting single-argument assertions without a diagnostic message.