C23 Modern C: auto, nullptr, constexpr, typeof, Attributes & Library Improvements

C23 Modern C: auto, nullptr, constexpr, typeof, Attributes & Library Improvements
Table of Contents
- How to Enable C23
- auto: Type Inference Without the Verbosity
- nullptr: The Type-Safe Null Pointer Constant
- constexpr: Compile-Time Constants
- typeof and typeof_unqual
- Standardized Attributes
- Enhanced Numerics: Binary Literals and Digit Separators
- Improved Standard Library
- stdbit.h: Portable Bit Operations
- Removed and Deprecated Features
- C23 vs C11 vs C99: Migration Guide
- Frequently Asked Questions
- Key Takeaway
How to Enable C23
auto: Type Inference Without the Verbosity
C23 repurposes the old, unused auto storage class specifier as a type inference keyword. The compiler deduces the type from the initializer, eliminating verbose type repetition:
[!NOTE] Unlike C++, C23
autocannot be used for function parameters or return types. It applies only to local variable declarations with initializers.
nullptr: The Type-Safe Null Pointer Constant
The old NULL macro is defined as 0 or (void*)0 — both are integers when used in non-pointer contexts, causing potential ambiguity. C23 introduces nullptr, a keyword of type nullptr_t that can only be used as a null pointer:
nullptr of type nullptr_t is implicitly convertible to any pointer type (including function pointers), but is NOT an integer — fixing the historical ambiguity.
constexpr: Compile-Time Constants
C23's constexpr is more limited than C++'s version but still extremely valuable. It declares compile-time constant variables (unlike #define, which is a preprocessor text substitution):
typeof and typeof_unqual
typeof(expression) yields the type of its argument at compile time — invaluable for writing truly generic macros without requiring _Generic:
Standardized Attributes
C23 standardizes attributes using [[attribute]] syntax (borrowed from C++). Previously, compilers had vendor-specific syntax (__attribute__((...))):
Enhanced Numerics: Binary Literals and Digit Separators
Improved Standard Library
memset_explicit: Secure Zeroing
Regular memset for zeroing sensitive data (passwords, encryption keys) can be optimized away by the compiler since the memory is "dead" after zeroing. memset_explicit is guaranteed never to be optimized away:
strdup and strndup (Standardized)
Previously POSIX extensions, now part of C23:
stdbit.h: Portable Bit Operations
C23 adds <stdbit.h> with standardized, efficient bit counting and manipulation functions — replacing the need for vendor-specific __builtin_popcount etc.:
These functions compile to single CPU instructions on x86-64 (POPCNT, BSR, LZCNT, TZCNT).
Removed and Deprecated Features
C23 removes features that were already deprecated or "optional" in C11:
| Removed | Replacement |
|---|---|
K&R style function definitions (int f(a,b) int a, b; {...}) | Modern: int f(int a, int b) {...} |
| Implicit int return type | Always specify return type explicitly |
gets() (already removed in C11) | Use fgets() |
Trigraph sequences (??= → #) | Use actual characters |
| Unprototyped function declarations | Always prototype functions |
C23 vs C11 vs C99: Migration Guide
| Feature | C99 | C11 | C23 |
|---|---|---|---|
bool, true, false | Macro via stdbool.h | Keyword | Built-in keyword |
_Generic | ❌ | ✅ | ✅ Improved |
nullptr | ❌ | ❌ | ✅ |
constexpr | ❌ | ❌ | ✅ |
auto (type inference) | ❌ | ❌ | ✅ |
typeof | GNU extension | GNU extension | ✅ Standardized |
Binary literals 0b... | GNU extension | GNU extension | ✅ Standardized |
Digit separators 1'000 | ❌ | ❌ | ✅ |
[[attributes]] | ❌ | Mixed | ✅ Full set |
memset_explicit | ❌ | ❌ | ✅ |
strdup | POSIX | POSIX | ✅ Standardized |
<stdbit.h> | ❌ | ❌ | ✅ |
Frequently Asked Questions
Is C23 backwards compatible with C11/C99 code? Almost entirely. The only breaking changes are removal of K&R style function definitions and trigraphs — both of which are extremely rare in modern code. Virtually all C11 and C99 code compiles cleanly under C23.
When will compilers fully support C23? GCC 14+ and Clang 18+ have comprehensive C23 support. MSVC (Microsoft Visual C++) has partial support. Check cppreference.com's C23 compiler support table for the current status per feature.
Can I use C23's auto in the same file as C++ code?
No — C and C++ are compiled separately. auto in C23 means type inference (same as in C++11+), but the rules differ. In C++, auto can be used for function return types and template parameters; in C23, it cannot.
Is constexpr in C23 the same as in C++?
No. C23's constexpr is more limited — it can only be applied to variables and only for values that can be computed at compile time from constant expressions. C++'s constexpr can additionally be applied to functions and enables compile-time function evaluation.
Key Takeaway
C23 demonstrates that C is still actively evolving. By adopting auto for type inference, nullptr for null safety, constexpr for zero-cost compile-time constants, typeof for powerful generic macros, and standardized [[attributes]] for optimization hints, you get a modern, expressive language that retains every bit of C's legendary performance.
These are not cosmetic changes — they directly reduce bugs (nullptr prevents null-as-integer confusion), improve tooling (constexpr variables are visible in debuggers), and enable better compiler optimization (attributes help the compiler understand your code's intent).
Read next: C Security & Hardening: Defeating Buffer Overflows →
Part of the C Mastery Course — 30 modules from C basics to expert systems engineering.
