KEMBAR78
C Programming C23 Deep Dive Into Modern Power For Systems | PDF | Integer (Computer Science) | Rounding
0% found this document useful (0 votes)
16 views155 pages

C Programming C23 Deep Dive Into Modern Power For Systems

The document is a comprehensive guide on the C23 programming standard, detailing its new features, enhancements, and the rationale behind its development. It covers topics such as decimal floating-point types, new preprocessor directives, and standard library enhancements, aimed at both systems and classic C programmers. The booklet emphasizes the continued relevance of C in modern programming contexts as of 2024/2025.

Uploaded by

arpansen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views155 pages

C Programming C23 Deep Dive Into Modern Power For Systems

The document is a comprehensive guide on the C23 programming standard, detailing its new features, enhancements, and the rationale behind its development. It covers topics such as decimal floating-point types, new preprocessor directives, and standard library enhancements, aimed at both systems and classic C programmers. The booklet emphasizes the continued relevance of C in modern programming contexts as of 2024/2025.

Uploaded by

arpansen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 155

C Programming

C23 Deep Dive into Modern Power for Systems and


Classic C Programmers

Prepared By Ayman Alheraki

simplifycpp.org

August 2025
Contents

Contents 2

Author’s Introduction 11

Preface 12
Purpose of the Booklet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Why C Still Matters in 2024/2025 . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Target Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1 Introduction to C23 18
1.1 Brief History of C Standards (C89 → C99 → C11 → C17 → C23) . . . . . 18
1.2 Goals of the C23 Revision . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3 Philosophy – Balancing Backward Compatibility with Modern Needs . . . 23
1.4 The New Predefined Macro __STDC_VERSION__ (202311L) . . . . . . 25
1.4.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.4.2 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.4.3 Significance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

2 New Language Features 27


2.1 Decimal Floating-Point Types (_Decimal32, _Decimal64, _Decimal128) . 27

2
3

2.1.1 Available Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27


2.1.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.1.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.1.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.2 Bit-Precise Integers (_BitInt) . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2.1 Syntax and Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.3 Binary Integer Constants (0b1010) . . . . . . . . . . . . . . . . . . . . . . 33
2.3.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.4 u8 Character Constants and Strings . . . . . . . . . . . . . . . . . . . . . . 36
2.4.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.4.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.4.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.4.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.5 Digit Separator ' in Literals . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.5.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.5.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.6 Empty Initializer ={} . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.6.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.6.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4

2.6.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42


2.6.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.7 Attributes ([[deprecated]], [[fallthrough]], [[nodiscard]], etc.) . . . . . . . . . 44
2.7.1 Common Attributes and Usage . . . . . . . . . . . . . . . . . . . . 44
2.7.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.7.3 Example in Context . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.7.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.8 Unnamed Parameters in Function Definitions . . . . . . . . . . . . . . . . 48
2.8.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.8.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.8.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.8.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.9 Improved Array Type Qualifications . . . . . . . . . . . . . . . . . . . . . 50
2.9.1 Concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.9.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.9.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.9.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.10 Single-Argument static_assert . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.10.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.10.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.10.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.10.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.11 Keywords Update (alignas, alignof, thread_local, true, false, nullptr) . . . 54
2.11.1 Updated Keywords and Usage . . . . . . . . . . . . . . . . . . . . . 54
2.11.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.11.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.11.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 56
5

2.12 Labels with Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57


2.12.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.12.2 Key Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.12.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.12.4 Notes for Practitioners . . . . . . . . . . . . . . . . . . . . . . . . . 58

3 Preprocessor and Compilation Features 59


3.1 New Directives (#elifdef, #elifndef, #warning, #embed) . . . . . . . . . . 59
3.1.1 #elifdef and #elifndef . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.1.2 #warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.1.3 #embed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.2 Feature-Test Macros (__STDC_IEC_60559_BFP__, etc.) . . . . . . . . 63
3.2.1 Key Macros and Their Purpose . . . . . . . . . . . . . . . . . . . . 63
3.2.2 Usage Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.3 Pragmas for Rounding Direction (STDC FENV_ROUND, STDC
FENV_DEC_ROUND) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.3.1 Key Pragmas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
3.3.2 Syntax Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

4 Standard Library Enhancements 69


4.1 New Headers (<stdbit.h>, <stdckdint.h>) . . . . . . . . . . . . . . . . . . 69
4.1.1 <stdbit.h> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
4.1.2 <stdckdint.h> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.2 Extended Math Functions (Binary & Decimal Floating-Point) . . . . . . . 72
4.2.1 Binary Floating-Point Extensions . . . . . . . . . . . . . . . . . . . 72
4.2.2 Decimal Floating-Point Extensions . . . . . . . . . . . . . . . . . . 72
4.3 UTF-8 Support (char8_t, mbrtoc8(), c8rtomb()) . . . . . . . . . . . . . . 75
4.3.1 char8_t Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
6

4.3.2 mbrtoc8() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.3.3 c8rtomb() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.4 Explicit Memory Clearing (memset_explicit()) . . . . . . . . . . . . . . . . 78
4.4.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.4.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.4.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.5 New POSIX-Like Functions (memccpy(), strdup(), gmtime_r(),
localtime_r()) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.5.1 memccpy() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.5.2 strdup() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.5.3 gmtime_r() and localtime_r() . . . . . . . . . . . . . . . . . . . . . 82
4.6 Extended strftime(), fscanf(), fprintf() . . . . . . . . . . . . . . . . . . . . 84
4.6.1 strftime() and wcsftime() Extensions . . . . . . . . . . . . . . . . . 84
4.6.2 fscanf() and fprintf() Extensions . . . . . . . . . . . . . . . . . . . 85
4.7 Formatting Updates – New Specifiers (b, H, D, DD, wN) . . . . . . . . . . 87
4.7.1 b – Binary Conversion Specifier . . . . . . . . . . . . . . . . . . . . 87
4.7.2 H, D, DD – Decimal Floating-Point Types . . . . . . . . . . . . . . 87
4.7.3 wN and wfN – Width-Specific Integer Modifiers . . . . . . . . . . . 88
4.8 New Library Test Macros (__STDC_VERSION_FENV_H__, etc.) . . . 90
4.8.1 Purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.8.2 Key Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.8.3 Example Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

5 Removed & Deprecated Features 93


5.1 Removed Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
5.1.1 Old-Style Function Declarations (K&R Style) . . . . . . . . . . . . 93
5.1.2 Non–Two’s Complement Integers . . . . . . . . . . . . . . . . . . . 94
5.1.3 Mixed Wide and Narrow String Literal Concatenation . . . . . . . 95
7

5.1.4 realloc(0) Behavior Undefined . . . . . . . . . . . . . . . . . . . . . 96


5.2 Deprecated Headers (<stdnoreturn.h>, <stdalign.h>, <stdbool.h>) . . . 99
5.2.1 <stdnoreturn.h> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
5.2.2 <stdalign.h> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.2.3 <stdbool.h> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.3 Deprecated Macros (__STDC_IEC_559__, DECIMAL_DIG,
INFINITY, NAN) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.3.1 __STDC_IEC_559__ and __STDC_IEC_559_COMPLEX__ 103
5.3.2 DECIMAL_DIG . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
5.3.3 INFINITY and NAN . . . . . . . . . . . . . . . . . . . . . . . . . . 105
5.4 Deprecated Features (_Noreturn, asctime(), ctime()) . . . . . . . . . . . . 107
5.4.1 _Noreturn Function Specifier . . . . . . . . . . . . . . . . . . . . . 107
5.4.2 asctime() and ctime() Functions . . . . . . . . . . . . . . . . . . . . 108
5.5 Guidance for Modern Replacements . . . . . . . . . . . . . . . . . . . . . . 111
5.5.1 Function Declarations . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.5.2 _Noreturn Specifier . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.5.3 Floating-Point Macros and Constants . . . . . . . . . . . . . . . . . 112
5.5.4 Alignment Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.5.5 Boolean Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.5.6 Time Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.5.7 Memory Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
5.5.8 General Guidance for Practitioners . . . . . . . . . . . . . . . . . . 114
5.5.9 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

6 Practical Migration Guide 116


6.1 Updating Existing C17 Codebases to C23 . . . . . . . . . . . . . . . . . . 116
6.1.1 Assess the Current Codebase . . . . . . . . . . . . . . . . . . . . . 116
6.1.2 Replace Deprecated Constructs . . . . . . . . . . . . . . . . . . . . 117
8

6.1.3 Adopt New C23 Language Features . . . . . . . . . . . . . . . . . . 118


6.1.4 Update Standard Library Usage . . . . . . . . . . . . . . . . . . . . 118
6.1.5 Test and Validate . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
6.1.6 Plan Gradual Migration . . . . . . . . . . . . . . . . . . . . . . . . 119
6.1.7 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
6.2 Handling Deprecated Features . . . . . . . . . . . . . . . . . . . . . . . . . 121
6.2.1 Identify Deprecated Features . . . . . . . . . . . . . . . . . . . . . 121
6.2.2 Replace Deprecated Headers and Macros . . . . . . . . . . . . . . . 121
6.2.3 Replace Deprecated Functions . . . . . . . . . . . . . . . . . . . . . 122
6.2.4 Refactor Old Function Declarations . . . . . . . . . . . . . . . . . . 123
6.2.5 Strategies for Safe Handling . . . . . . . . . . . . . . . . . . . . . . 124
6.2.6 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
6.3 Ensuring Portability Across Compilers . . . . . . . . . . . . . . . . . . . . 125
6.3.1 Use Standard Feature-Test Macros . . . . . . . . . . . . . . . . . . 125
6.3.2 Avoid Compiler-Specific Extensions . . . . . . . . . . . . . . . . . . 125
6.3.3 Test Across Multiple Compilers . . . . . . . . . . . . . . . . . . . . 126
6.3.4 Handle Platform-Specific Data Types . . . . . . . . . . . . . . . . . 127
6.3.5 Standardize Floating-Point Behavior . . . . . . . . . . . . . . . . . 127
6.3.6 Document Compiler Assumptions . . . . . . . . . . . . . . . . . . . 128
6.3.7 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
6.4 Differences from C++ Features . . . . . . . . . . . . . . . . . . . . . . . . 129
6.4.1 nullptr Constant . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
6.4.2 Attributes ([[nodiscard]], [[deprecated]], etc.) . . . . . . . . . . . . . 129
6.4.3 static_assert Keyword . . . . . . . . . . . . . . . . . . . . . . . . . 130
6.4.4 Type Safety and Keywords . . . . . . . . . . . . . . . . . . . . . . 130
6.4.5 Intent and Philosophy . . . . . . . . . . . . . . . . . . . . . . . . . 131
6.4.6 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
9

7 Future of C Beyond C23 132


7.1 Potential Directions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
7.1.1 Memory Safety Enhancements . . . . . . . . . . . . . . . . . . . . . 132
7.1.2 Tooling Improvements . . . . . . . . . . . . . . . . . . . . . . . . . 133
7.1.3 Optional Borrow-Checking or Ownership Semantics . . . . . . . . . 133
7.1.4 Other Potential Directions . . . . . . . . . . . . . . . . . . . . . . . 134
7.1.5 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
7.2 Comparison with Rust, Go, and Modern Systems Languages . . . . . . . . 135
7.2.1 Memory Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
7.2.2 Concurrency and Parallelism . . . . . . . . . . . . . . . . . . . . . 135
7.2.3 Type Systems and Expressiveness . . . . . . . . . . . . . . . . . . . 136
7.2.4 Tooling and Ecosystem . . . . . . . . . . . . . . . . . . . . . . . . . 137
7.2.5 Philosophy and Use Cases . . . . . . . . . . . . . . . . . . . . . . . 137
7.2.6 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
7.3 Why C Remains Relevant in Embedded and Systems Programming . . . . 139
7.3.1 Direct Hardware Access . . . . . . . . . . . . . . . . . . . . . . . . 139
7.3.2 Minimal Runtime and Predictable Behavior . . . . . . . . . . . . . 139
7.3.3 Portability and Standardization . . . . . . . . . . . . . . . . . . . . 139
7.3.4 Rich Ecosystem and Proven Toolchains . . . . . . . . . . . . . . . . 140
7.3.5 Performance and Efficiency . . . . . . . . . . . . . . . . . . . . . . 140
7.3.6 Modern Enhancements in C23 . . . . . . . . . . . . . . . . . . . . . 140
7.3.7 Key Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

Appendices 142
Full Reference Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Sample Code Listings (Ready-to-Compile) . . . . . . . . . . . . . . . . . . . . . 146
References to WG14 Documents) . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10

References 153
Author’s Introduction

This booklet is designed for professional C programmers who use the language daily in
system development, embedded programming, or high-performance applications. Its
purpose is to serve as a quick, practical guide to transition existing knowledge to C23,
highlighting new features, deprecated items, and modern best practices.
By focusing on concise explanations, ready-to-compile examples, and reference tables,
this guide allows developers to quickly adopt C23 in their projects while maintaining
compatibility with existing codebases. It is intended as a hands-on, professional
reference for engineers who want to stay up-to-date with the latest C standard without
losing productivity.
This booklet emphasizes clarity, efficiency, and professional applicability, making it an
essential companion for any developer seeking to leverage the modern power of C23 in
real-world applications.

11
Preface

Purpose of the Booklet


The purpose of this booklet is to provide professional programmers, system developers,
and embedded engineers with a practical and focused guide to the latest revision of the
C programming language standard: C23 (ISO/IEC 9899:2024).
C has remained one of the most influential and enduring programming languages
since its creation more than five decades ago. Despite the rise of higher-level and
safer alternatives, C continues to be the foundation of modern operating systems,
compilers, embedded platforms, and performance-critical applications. The release of
C23 introduces a significant set of language and library updates that modernize C while
retaining its simplicity, efficiency, and compatibility.
This booklet is designed to serve three main purposes:

1. Highlight New Features

• Present the language and library additions in C23 with clear explanations
and concise examples.
• Show how these features address long-standing limitations or align with
modern development practices.

2. Guide Migration and Adoption

12
13

• Provide system programmers with practical instructions for transitioning


from C17 to C23.
• Clarify how to replace deprecated features and adopt safer, more expressive
constructs.

3. Offer a Professional Reference

• Supply quick-access tables, lists of new keywords, attributes, macros, and


library functions.
• Serve as a compact resource (under 150 pages) for day-to-day use in systems,
embedded, and performance-oriented programming.

By focusing on clarity, depth, and applicability, this booklet aims to bridge the gap
between formal standard documents and the real-world needs of programmers who
build critical software systems. It is not a full tutorial on C but a targeted guide to
C23—what is new, what has changed, and why it matters.
14

Why C Still Matters in 2024/2025


C continues to be one of the most relevant programming languages in modern software
development, even as newer languages such as Rust, Go, and modern C++ gain
attention. Its persistence is not an accident but the result of core strengths that remain
unmatched in specific domains.

1. Foundation of Modern Systems

• Operating systems, device drivers, embedded firmware, and critical libraries


are overwhelmingly written in C. Its close relationship to hardware makes
it indispensable for low-level programming where direct memory control,
deterministic performance, and small runtime footprints are essential.

2. Portability and Longevity

• C codebases can run across architectures and platforms with minimal


changes. Standards like C23 ensure that this portability is maintained while
aligning with modern hardware and software practices. This long-term
stability makes C a safe investment for infrastructure software that must
outlive hardware generations.

3. Efficiency and Control

• C gives programmers direct access to memory, data representation, and


system resources with little abstraction overhead. This balance of power
and performance makes it the language of choice for applications where
predictability and resource constraints are critical.

4. Interoperability
15

• Nearly every modern programming language interoperates with C libraries.


From Python and Java to Rust and Go, C remains the “lingua franca” for
cross-language integration, ensuring that C-based APIs and libraries remain
widely useful.

5. Evolving Standards

• C23 demonstrates that the language is not stagnant. New features such as
safer integer handling, better Unicode support, attributes, and modernized
libraries keep C aligned with the needs of today’s developers while retaining
backward compatibility.

In 2024 and beyond, C remains a strategic language: it is lightweight, proven, and


foundational to computing. For system programmers, embedded engineers, and
developers of performance-critical applications, learning and applying C23 is not
simply about keeping up with a standard—it is about strengthening the skill set that
underpins the software ecosystem itself.
16

Target Audience
This booklet is written for professionals who already possess experience with the C
language or system-level programming and who seek to understand the implications
of the C23 standard. It is not an introductory tutorial, but a focused resource for those
who apply C in performance-critical or low-level contexts.
The primary audiences are:

1. Professional Programmers

• Developers who maintain or extend large C codebases.

• Those who need a concise but practical reference to new features,


deprecations, and migration strategies from C17 to C23.

2. System Developers

• Engineers working on operating systems, compilers, virtual machines, or


runtime libraries.

• Professionals who must track language evolution to ensure compatibility,


efficiency, and standards compliance.

3. Embedded Engineers

• Developers creating firmware, device drivers, and embedded software where


memory control, execution speed, and hardware integration are central.

• Engineers who benefit from the new precision types, safer integer handling,
and explicit memory functions introduced in C23.
17

By focusing on these groups, the booklet ensures that examples, explanations, and
references are aligned with real-world use cases rather than purely academic concerns.
The content emphasizes clarity, portability, and practical adoption, making it a
valuable addition to the professional toolkit of anyone who relies on C for building
robust systems.
Chapter 1

Introduction to C23

1.1 Brief History of C Standards (C89 → C99 → C11 → C17 →


C23)
The C programming language has evolved through several standardized revisions,
each responding to technological changes and the practical needs of programmers.
Understanding this progression provides essential context for the updates introduced
in C23.

1. C89 / ANSI C (1989)

• The first official standard, produced by ANSI, unified diverse compiler


dialects.
• Introduced function prototypes, the standard library headers, and a
consistent definition of the language.
• Ensured portability across platforms, establishing C as the foundation of
system and application development.

18
19

2. C99 (1999)

• Added features to support modern programming practices and numerical


computing.

• Key updates: inline functions, variable-length arrays (VLAs), new data types
(long long, complex numbers), flexible array members, and the // single-line
comment style.

• Expanded the standard library with math functions, integer types in


<stdint.h>, and more precise floating-point control.

3. C11 (2011)

• Focused on safety, concurrency, and internationalization.

• Introduced _Atomic types, thread support (<threads.h>), improved


Unicode handling, and static assertions.

• Added optional bounds-checking interfaces and aligned allocation.

4. C17 (2017)

• A maintenance release rather than a feature-rich update.

• Resolved defects, clarified wording, and aligned with C++ where reasonable.

• Reinforced stability for existing codebases, preparing the ground for larger
updates.

5. C23 (2024)

• The most significant update since C99, balancing modernization with


backward compatibility.
20

• Introduces new data types (_BitInt, decimal floating-point), attributes,


UTF-8 support, digit separators, binary constants, and safer memory
handling functions.
• Deprecates outdated headers and removes features inconsistent with modern
hardware and practices (such as non–two’s complement integers).
• Reaffirms C’s relevance by addressing both system-level efficiency and
developer productivity.

This historical trajectory demonstrates that while C remains simple and close to the
hardware, it continues to adapt. Each standard refines the language to meet new
demands without abandoning its original design philosophy of efficiency, portability,
and direct control.
21

1.2 Goals of the C23 Revision


The C23 revision was developed to modernize the language while preserving its long-
standing strengths of portability, efficiency, and predictability. Unlike languages that
evolve rapidly, C maintains a conservative approach to change, ensuring stability for
legacy codebases while addressing the needs of contemporary systems programming.
The key goals of C23 can be summarized as follows:

1. Enhance Portability Across Modern Architectures

• Update the standard to reflect the dominance of two’s complement


arithmetic, IEEE-754 floating-point, and contemporary processor designs.
• Introduce feature-test macros and library version macros to help developers
write portable code across compilers and platforms.

2. Introduce Safer and More Expressive Constructs

• Provide attributes such as [[nodiscard]] and [[deprecated]] to reduce errors at


compile time.
• Add explicit functions like memset_explicit() to improve memory safety in
security-sensitive contexts.
• Extend support for precise integer and floating-point types, enabling
developers to match data representation with application requirements.

3. Improve Internationalization and Character Handling

• Standardize UTF-8 support through char8_t and related library functions.


• Clarify the use of u8 string literals to ensure consistent handling of encoded
text.
22

4. Align with Modern Programming Practices

• Introduce binary literals, digit separators, empty initializers, and a nullptr


constant to simplify coding and improve readability.
• Upgrade existing constructs (e.g., thread_local, static_assert, alignas) from
macros to full keywords.

5. Streamline the Language by Removing Obsolete Features

• Deprecate headers and macros that overlap with newer mechanisms.


• Remove legacy features such as old-style function declarations and non–two’s
complement integers, reflecting modern compiler and hardware assumptions.

6. Support Long-Term Maintainability of C Codebases

• Provide clearer specifications, standardized attributes, and additional library


functions to reduce reliance on non-standard extensions.
• Ensure that professional developers can update legacy systems incrementally
while adopting modern features where beneficial.

In short, the C23 revision seeks to balance modernization with stability. It adds
tools that improve safety, clarity, and portability while eliminating features that
are inconsistent with today’s hardware and programming environments. For system
programmers, this ensures that C remains a practical, reliable, and forward-looking
language in 2024 and beyond.
23

1.3 Philosophy – Balancing Backward Compatibility with


Modern Needs
From its origin, C has been defined by two guiding principles: remain close to the
hardware and remain portable across platforms. Every revision of the standard must
respect these principles, ensuring that existing C programs continue to function while
the language adapts to contemporary requirements. C23 continues this tradition by
carefully balancing backward compatibility with modernization.

1. Preserving Legacy Code

• The C ecosystem includes decades of critical code in operating systems,


compilers, databases, and embedded software. Breaking compatibility would
risk destabilizing long-standing infrastructure. C23 therefore maintains core
syntax and semantics, allowing older codebases to compile with minimal
changes.

2. Gradual Modernization

• Rather than dramatic redesign, the standard evolves through incremental


features such as digit separators, binary literals, and attributes. These
additions improve clarity and safety without disrupting the established
mental model of C programmers.

3. Deprecation Instead of Abrupt Removal

• Obsolete features, such as <stdbool.h> or _Noreturn, are marked as


deprecated before eventual removal. This staged approach gives developers
time to transition and keeps compilers aligned with both modern and legacy
practices.
24

4. Alignment with Hardware Realities

• Assumptions that no longer reflect current architectures—such as support


for non–two’s complement integers—are removed. At the same time, new
facilities like _BitInt and decimal floating types reflect the precision and
range required by modern processors.

5. Selective Inspiration from Other Languages

• C23 adopts certain concepts familiar from C++ (e.g., nullptr, standardized
attributes) but only where they enhance safety and clarity without
introducing excessive abstraction. This ensures C retains its distinct
character while benefiting from proven ideas.

6. Stability for the Long Term

• Each revision must serve as a reliable base for years of development. By


avoiding radical changes, C23 ensures that future tools, compilers, and
libraries can interoperate smoothly with decades of existing C software.

In essence, the philosophy of C23 is one of evolution, not revolution. It strengthens


the language with modern tools and safer constructs while preserving the simplicity,
predictability, and control that define C. For professional programmers and system
developers, this balance ensures that C remains both relevant today and dependable
tomorrow.
25

1.4 The New Predefined Macro __STDC_VERSION__


(202311L)
Every C standard introduces or updates a macro in <stddef.h> to allow programs to
detect which version of the standard the compiler conforms to. This mechanism enables
conditional compilation, ensuring that code can adapt to features available in a given
revision.
In C23, the predefined macro __STDC_VERSION__ has been updated to:

#define __STDC_VERSION__ 202311L

• 2023 refers to the year in which the standard was completed.

• 11 corresponds to the month (November) of finalization.

• L indicates a long integer literal.

1.4.1 Purpose
The macro allows developers to write portable code that can:

1. Check whether the compiler supports C23 features.

2. Fall back to earlier constructs if compiled under C17 or older.

3. Use feature-based conditional compilation to avoid non-portable assumptions.

1.4.2 Example Usage


26

#include <stdio.h>

int main(void) {
#if __STDC_VERSION__ >= 202311L
printf(”Compiled with C23 or later\n”);
#elif __STDC_VERSION__ >= 201710L
printf(”Compiled with C17\n”);
#elif __STDC_VERSION__ >= 201112L
printf(”Compiled with C11\n”);
#else
printf(”Compiled with an older C standard\n”);
#endif
}

1.4.3 Significance
• Provides a standard way to confirm compiler compliance with C23.

• Facilitates long-term maintenance of libraries and frameworks targeting multiple


C standards.

• Acts as a baseline identifier, complemented by feature-test macros (e.g.,


__STDC_IEC_60559_BFP__) that detect optional capabilities.

By updating __STDC_VERSION__, C23 preserves the consistent mechanism


programmers have relied on since C90 while signaling the availability of the most
modern features of the language.
Chapter 2

New Language Features

2.1 Decimal Floating-Point Types (_Decimal32, _Decimal64,


_Decimal128)
C23 introduces decimal floating-point types to complement the existing binary
floating-point types (float, double, long double). Decimal floating-point provides
precise representation of decimal fractions, which is critical in financial, commercial,
and scientific applications where rounding errors from binary floating-point are
unacceptable.

2.1.1 Available Types


• _Decimal32 – 7 decimal digits of precision.

• _Decimal64 – 16 decimal digits of precision.

• _Decimal128 – 34 decimal digits of precision.

27
28

These types follow the IEEE-754-2008 standard for decimal arithmetic, ensuring
predictable and standardized behavior across platforms.

2.1.2 Key Advantages


1. Exact Decimal Representation

• Eliminates typical rounding errors when representing decimal fractions (e.g.,


0.1).

2. Improved Portability for Financial Software

• Calculations involving currency and fixed-point arithmetic behave


consistently on all compliant systems.

3. Extended Math Library Support

• C23 provides decimal versions of mathematical functions, such as


quantizedN(), encodebindN(), decodedecdN(), and more.

2.1.3 Example Usage

#include <stdio.h>
#include <decimal/decimal.h> // Optional: compiler-specific support

int main(void) {
_Decimal32 a = 1.05dd32;
_Decimal32 b = 0.42dd32;
_Decimal32 sum = a + b;

printf(”Sum: %.7Dd\n”, sum); // Decimal floating-point format


29

return 0;
}

2.1.4 Notes for Practitioners


• Decimal floating-point literals use the suffixes df32, df64, or df128 depending on
the type.

• They coexist with binary floating-point types; conversions between decimal and
binary types are supported but may involve rounding.

• These types are most useful in domains requiring exact decimal arithmetic, such
as accounting, banking, and scientific measurements.

By introducing _Decimal32, _Decimal64, and _Decimal128, C23 addresses a long-


standing gap in the language: providing a native, standardized solution for precise
decimal calculations.
30

2.2 Bit-Precise Integers (_BitInt)


C23 introduces bit-precise integer types through the _BitInt(N) syntax, allowing
programmers to declare integers with an exact number of bits. This feature provides
fine-grained control over storage and arithmetic precision, which is essential in low-level,
embedded, and performance-critical applications.

2.2.1 Syntax and Usage

_BitInt(3) a; // 3-bit signed integer


unsigned _BitInt(5) b; // 5-bit unsigned integer

• N specifies the number of bits (1 � N � implementation-defined maximum,


typically 128).

• Bit-precise integers can be signed (default) or unsigned.

• Standard arithmetic operators (+, -, *, /) and bitwise operators (&, |, ^, ~) are


supported.

2.2.2 Key Advantages


1. Memory Efficiency

• Reduces storage requirements for integers that do not need full-width


representation.

• Particularly useful in embedded systems, network protocols, and packed data


structures.
31

2. Predictable Overflow Behavior

• Arithmetic overflow follows two’s complement rules, making behavior


deterministic for hardware-level operations.

3. Improved Portability for Low-Level Systems

• Guarantees precise bit-widths across platforms, unlike traditional integer


types where int size may vary.

2.2.3 Example Usage

#include <stdio.h>

int main(void) {
_BitInt(7) sensor_value = 100;
unsigned _BitInt(4) flags = 0b1010;

printf(”Sensor: %d, Flags: %u\n”, sensor_value, flags);


return 0;
}

2.2.4 Notes for Practitioners


• _BitInt types cannot exceed implementation-defined limits, which may vary by
compiler.

• Interoperability with standard integer types requires explicit casting in some


cases.
32

• They are ideal for hardware registers, bit fields, and protocol encoding, providing
a level of precision that standard integers cannot guarantee.

By adding _BitInt, C23 gives developers a native, portable mechanism to work


with integers of arbitrary precision, enhancing both safety and efficiency in low-level
programming.
33

2.3 Binary Integer Constants (0b1010)


C23 introduces binary integer constants, allowing integer values to be expressed directly
in base-2 notation. This addition improves readability and clarity when dealing with bit
masks, flags, and low-level hardware operations.

2.3.1 Syntax

int mask = 0b10101010; // binary literal


unsigned _BitInt(8) flags = 0b1101; // binary literal with bit-precise integer

• Binary constants start with the prefix 0b or 0B.

• Can be combined with digit separators (') for readability:

int pattern = 0b1010'1101; // easier to read than 0b10101101

• Compatible with standard integer types (int, long, _BitInt, etc.).

2.3.2 Key Advantages


1. Clarity in Bitwise Operations

• Makes it immediately obvious which bits are set or cleared.

• Reduces errors in masks and flag definitions.

2. Simplifies Embedded and Systems Programming


34

• Directly matches the binary layout of hardware registers.

• Useful in low-level firmware, protocol parsing, and device drivers.

3. Enhanced Readability

• Avoids manual conversion from hexadecimal or decimal when expressing bit


patterns.

2.3.3 Example Usage

#include <stdio.h>

int main(void) {
int permissions = 0b1101; // read/write/execute bits
int mask = 0b0001;

if (permissions & mask) {


printf(”Execute permission enabled.\n”);
}
return 0;
}

2.3.4 Notes for Practitioners


• Binary literals can be signed or unsigned, following standard integer rules.

• They are fully compatible with arithmetic and bitwise operators.

• Combined with _BitInt, they allow precise, readable representation of hardware-


level data.
35

Binary integer constants in C23 are a small but impactful feature, giving programmers
a clear, concise way to work directly with bits, improving both correctness and
maintainability in system-level code.
36

2.4 u8 Character Constants and Strings


C23 introduces UTF-8 character constants and string literals using the u8 prefix. This
addition enhances internationalization support, allowing programs to handle Unicode
text in a standardized and portable way.

2.4.1 Syntax

char8_t ch = u8'A'; // UTF-8 character constant


char8_t str[] = u8”Hello”; // UTF-8 string literal

• u8 indicates that the constant or string is UTF-8 encoded.

• The type for u8 string literals is char8_t[], not char[], ensuring type safety.

2.4.2 Key Advantages


1. Standardized UTF-8 Support

• Avoids ambiguity in encoding for international text.


• Facilitates safe manipulation of multibyte strings.

2. Interoperability with Modern Libraries

• Compatible with functions designed for UTF-8 data, including standard


library functions in C23.
• Supports conversions between char, wchar_t, and char8_t.

3. Improved Readability and Safety


37

• Using u8 explicitly indicates the intended encoding, reducing bugs from


implicit conversions or incorrect assumptions.

2.4.3 Example Usage

#include <stdio.h>
#include <uchar.h>

int main(void) {
char8_t greeting[] = u8”�����”; // Arabic ”Hello”
printf(”%s\n”, (const char *)greeting); // cast for printf compatibility
return 0;
}

2.4.4 Notes for Practitioners


• u8 literals are immutable arrays of char8_t with UTF-8 encoding.

• When interacting with legacy APIs, casting to char* may be required, but
internal operations should use char8_t to maintain safety.

• Combined with C23’s updated library functions (mbrtoc8, c8rtomb), u8 literals


enable robust, portable Unicode handling.

By adding u8 character constants and strings, C23 brings modern Unicode support to
the language, making it suitable for international applications while maintaining C’s
efficiency and low-level control.
38

2.5 Digit Separator ' in Literals


C23 introduces the single-quote (') as a digit separator in numeric literals, improving
readability for large numbers and complex constants. This feature is purely syntactic
and does not affect the value of the literal.

2.5.1 Syntax

int large_number = 1'000'000; // One million


unsigned long mask = 0b1111'0000; // Binary literal with separator
double pi = 3.1415'9265; // Floating-point literal

• Can be used in decimal, binary, octal, and hexadecimal literals.

• Enhances visual grouping of digits, making numbers easier to read and verify.

2.5.2 Key Advantages


1. Improved Readability

• Reduces errors in manually reading or typing large numeric literals.

• Makes bit masks, memory sizes, and constants more understandable at a


glance.

2. Maintains Full Compatibility

• Compilers ignore the ' when interpreting the numeric value.

• Works with all standard arithmetic and logical operations.


39

3. Consistency Across Literal Types

• Can be applied to integers (int, _BitInt), floating-point numbers, and binary


literals.

• Supports modern coding standards and professional style guidelines.

2.5.3 Example Usage

#include <stdio.h>

int main(void) {
_BitInt(16) flags = 0b1010'1100'0011'1111;
long memory = 16'384'000; // bytes
double e = 2.7182'8182;

printf(”Flags: %u, Memory: %ld, e: %.8f\n”, flags, memory, e);


return 0;
}

2.5.4 Notes for Practitioners


• Digit separators cannot appear at the start or end of a literal, or adjacent to the
decimal point in floating-point numbers.

• They are intended purely for clarity and maintainability; numeric calculations
remain unaffected.

• When combined with binary or hexadecimal literals, separators make patterns in


bitfields immediately visible.
40

The introduction of the digit separator in C23 is a small but highly practical
improvement, enhancing code readability and reducing errors in low-level, embedded,
and systems programming contexts.
41

2.6 Empty Initializer ={}


C23 introduces the empty initializer ={}, allowing variables, arrays, and structures
to be explicitly zero-initialized or default-initialized in a concise, readable way. This
feature simplifies initialization syntax while maintaining type safety and predictability.

2.6.1 Syntax

int x = {}; // x is zero-initialized


int array[5] = {}; // all elements are zero
struct Point { int x, y; } p = {}; // all members zero-initialized

• Works with scalars, arrays, structs, and unions.

• Eliminates the need to manually set values to zero or default.

2.6.2 Key Advantages


1. Improved Readability

• Signals clearly that the intention is to initialize to zero or default values.


• Reduces clutter in code compared to manual initialization.

2. Safety and Predictability

• Guarantees that uninitialized fields are set to a known state.


• Prevents undefined behavior due to uninitialized variables.

3. Consistency Across Types


42

• Works uniformly for scalar types, aggregates, and arrays, making


initialization patterns more predictable.

2.6.3 Example Usage

#include <stdio.h>

struct Config {
int width;
int height;
int flags;
};

int main(void) {
int counter = {};
int buffer[10] = {};
struct Config cfg = {}; // width, height, flags set to 0

printf(”Counter: %d, Buffer[0]: %d, Config.width: %d\n”,


counter, buffer[0], cfg.width);
return 0;
}

2.6.4 Notes for Practitioners

• Empty initializer is particularly useful for aggregates when default zeroing is


desired.

• Works seamlessly with existing aggregate initialization rules.


43

• Enhances clarity in system and embedded code, where predictable default values
are critical.

The ={} initializer in C23 is a minor but highly practical feature, improving code
readability, safety, and maintainability across a variety of types and programming
contexts.
44

2.7 Attributes ([[deprecated]], [[fallthrough]], [[nodiscard]], etc.)


C23 introduces standardized attributes to provide compile-time hints and enforce
safer coding practices. Attributes are enclosed in double square brackets [[...]] and
can be applied to functions, variables, and statements. They improve readability,
maintainability, and correctness without affecting runtime behavior.

2.7.1 Common Attributes and Usage


1. [[deprecated]]

• Marks functions, variables, or types as obsolete.

• Compilers issue a warning if deprecated entities are used.

[[deprecated(”Use new_function() instead”)]]


void old_function() { }

int main(void) {
old_function(); // Compiler warns: deprecated
return 0;
}

1. [[nodiscard]]

• Indicates that the return value should not be ignored.

• Prevents errors when a function’s result must be used.


45

[[nodiscard]]
int compute_value() { return 42; }

int main(void) {
compute_value(); // Warning: return value ignored
int x = compute_value(); // Correct usage
return 0;
}

1. [[fallthrough]]

• Explicitly documents intentional fall-through in switch statements.


• Eliminates warnings about missing break statements.

switch (n) {
case 1:
// some code
[[fallthrough]];
case 2:
// continues intentionally
break;
}

1. Other Attributes

• [[noreturn]] – marks functions that do not return (e.g., exit() or abort()).


• [[maybe_unused]] – suppresses warnings for unused variables or functions.
• [[unsequenced]] and [[reproducible]] – provide hints for floating-point
operations and deterministic computation.
46

2.7.2 Key Advantages


• Safety: Enforces correct usage patterns at compile time.

• Clarity: Makes programmer intentions explicit, improving maintainability.

• Portability: Standardized syntax ensures consistent compiler behavior across


platforms.

2.7.3 Example in Context

#include <stdio.h>
#include <stdlib.h>

[[nodiscard]] int calculate(int x) { return x * 2; }


[[deprecated]] void old_api() { }

int main(void) {
int value = calculate(5);
old_api(); // Compiler warns
printf(”Value: %d\n”, value);
return 0;
}

2.7.4 Notes for Practitioners


• Attributes are optional hints, not mandatory behavior changes.

• They replace non-standard compiler-specific extensions, providing a portable,


standardized mechanism.
47

• Useful in large systems and library development where warnings help prevent
subtle bugs.

C23 attributes bring compile-time safety, clarity, and maintainability to C programs,


enabling professional developers to write more robust and self-documenting code.
48

2.8 Unnamed Parameters in Function Definitions


C23 allows unnamed parameters in function definitions, enabling developers to ignore
unused arguments explicitly without needing to name them or generate warnings. This
is particularly useful for callback functions, interface implementations, or APIs where
some parameters are required by the signature but not used in every implementation.

2.8.1 Syntax

void callback(int, int used) {


// First parameter is unnamed and unused
printf(”Used parameter: %d\n”, used);
}

• The unnamed parameter is declared without a name but retains its type.

• Can be combined with attributes like [[maybe_unused]] for additional clarity.

2.8.2 Key Advantages


1. Suppresses Warnings for Unused Parameters

• Eliminates compiler warnings without introducing dummy variable names.

2. Improves Code Clarity

• Signals clearly that certain parameters are intentionally unused.


• Reduces clutter in functions with long or complex signatures.

3. Maintains Compatibility with Function Signatures


49

• Allows functions to conform to required prototypes (e.g., callback APIs)


while ignoring irrelevant arguments.

2.8.3 Example Usage

#include <stdio.h>

void log_event(int, int level, const char *msg) {


// First parameter is unused
if (level > 1) {
printf(”LOG: %s\n”, msg);
}
}

int main(void) {
log_event(0, 2, ”System initialized”);
return 0;
}

2.8.4 Notes for Practitioners


• Unnamed parameters can only be used in definitions, not in declarations.

• Useful in system programming, embedded firmware, and callback-heavy APIs.

• Can be combined with _BitInt or other C23 types for concise, modern code.

By supporting unnamed parameters, C23 enables cleaner, warning-free function


definitions while preserving full type safety and signature compatibility, enhancing
maintainability in professional codebases.
50

2.9 Improved Array Type Qualifications


C23 refines array type qualifications to ensure that const, volatile, and restrict qualifiers
apply consistently to both the array and its element type. This clarification improves
type safety, code readability, and predictable behavior in complex array manipulations.

2.9.1 Concept
Previously, qualifiers on array types could be ambiguous:

const int arr[5]; // Is the array constant or its elements?

C23 standardizes this so that CVR qualifiers for arrays are identical to those of the
elements, reducing confusion and improving compiler diagnostics.

2.9.2 Key Advantages


1. Predictable Type Behavior

• Ensures that array-level qualifiers behave consistently with element-level


qualifiers.

• Prevents subtle bugs in pointer arithmetic and function arguments.

2. Enhanced Safety

• Helps catch unintended modifications of arrays or elements at compile time.

• Aligns array semantics with modern type rules in system programming.

3. Improved Compiler Optimization


51

• Clearer type qualifications allow compilers to better optimize memory access


and inline operations.

2.9.3 Example Usage

void process_array(const int arr[10]) {


// arr elements are const; cannot be modified
for (int i = 0; i < 10; i++) {
printf(”%d ”, arr[i]);
}
}

• The array type and element type are treated consistently, enforcing correct usage
of const.

2.9.4 Notes for Practitioners


• Applies to all CVR qualifiers: const, volatile, restrict.

• Especially useful in embedded systems and low-level libraries where pointer


aliasing and memory safety are critical.

• Works seamlessly with other C23 features like _BitInt arrays or u8 strings.

With improved array type qualifications, C23 ensures consistent, safe, and predictable
behavior for arrays, enhancing reliability in professional and system-level programming.
52

2.10 Single-Argument static_assert


C23 enhances the static_assert mechanism, allowing it to be used with a single
argument. This provides simpler compile-time assertions while maintaining type safety
and code clarity.

2.10.1 Syntax

static_assert(sizeof(int) == 4); // Single-argument usage

• Previously, static_assert required two arguments: a condition and a string


message.

• Now, a single argument is sufficient, and the compiler provides a default message
if the assertion fails.

2.10.2 Key Advantages


1. Simpler and Cleaner Code

• Reduces boilerplate when a descriptive message is unnecessary.

2. Compile-Time Safety

• Checks conditions during compilation, preventing unsafe or inconsistent


assumptions from propagating to runtime.

3. Maintains Full Backward Compatibility

• Two-argument form is still supported for custom messages.


• Integrates seamlessly with C23 keywords and type traits.
53

2.10.3 Example Usage

#include <assert.h>

static_assert(sizeof(long) >= 8); // Ensure platform supports 64-bit long

int main(void) {
return 0;
}

• If the condition is false, the compiler generates a diagnostic and stops


compilation.

2.10.4 Notes for Practitioners


• Ideal for type-size checks, alignment constraints, and compile-time feature
validation.

• Works for scalars, arrays, and user-defined types.

• Enhances robustness of libraries and system code, especially when combined with
alignas and _BitInt types.

The single-argument static_assert in C23 simplifies compile-time verification, providing


concise, safe, and maintainable assertions for professional C programmers.
54

2.11 Keywords Update (alignas, alignof, thread_local, true, false,


nullptr)
C23 officially promotes several previously macro-based or optional features to reserved
keywords, improving type safety, clarity, and compiler diagnostics. These updates
ensure consistent, modern usage across all compliant C23 programs.

2.11.1 Updated Keywords and Usage


1. alignas and alignof

• Control and query the alignment of types and variables.


• Previously macros; now reserved keywords.

struct alignas(16) Vector { float x, y, z, w; };


printf(”Alignment: %zu\n”, alignof(Vector));

1. thread_local

• Declares variables that exist once per thread, enabling thread-safe data
without locks.

thread_local int counter = 0;

1. Boolean Constants: true and false

• Now standardized as keywords.


55

• Improves clarity and avoids conflicts with macro definitions.

_Bool flag = true;


if (!flag) { /* ... */ }

1. nullptr Constant and nullptr_t Type

• Introduces a null pointer constant distinct from integer zero.


• Enhances type safety when assigning or comparing null pointers.

int *ptr = nullptr;


if (ptr == nullptr) { /* safe check */ }

2.11.2 Key Advantages


• Type Safety: Prevents accidental misuse of null pointers, booleans, and
alignments.

• Clarity: Makes code self-documenting and consistent across modern C programs.

• Portability: Standardized keywords reduce reliance on compiler-specific macros.

2.11.3 Example Usage

#include <stdio.h>
#include <stdalign.h>

thread_local int id = 0;
56

struct alignas(8) Point { double x, y; };

int main(void) {
Point p;
int *ptr = nullptr;
_Bool active = true;

printf(”Point alignment: %zu\n”, alignof(Point));


if (ptr == nullptr && active) {
printf(”Thread-local id: %d\n”, id);
}
return 0;
}

2.11.4 Notes for Practitioners


• These keyword updates replace legacy macros (e.g., <stdalign.h>, <stdbool.h>).

• Encourage modern C23-compliant code, especially in systems, embedded, and


multi-threaded applications.

• Fully compatible with existing type definitions, _BitInt, and decimal floating-
point types.

By standardizing these features as keywords, C23 improves safety, expressiveness, and


maintainability for professional C programmers.
57

2.12 Labels with Declarations


C23 allows labels to be immediately followed by variable declarations, improving code
clarity and reducing boilerplate in structured control flows, particularly in goto-based or
state-machine programming.

2.12.1 Syntax

start:
int counter = 0; // Declaration directly after label
counter++;
if (counter < 5) goto start;

• Previously, C required labels to be followed by statements only, not declarations.

• Now, both declarations and statements are valid after a label.

2.12.2 Key Advantages


1. Cleaner Code Structure

• Eliminates the need for extra blocks just to declare variables after a label.

2. Improved Readability

• Makes the purpose and initialization of variables near the label explicit.

3. Practical for Low-Level Programming

• Useful in embedded systems, OS kernels, and state machines where labels


and goto statements are common.
58

2.12.3 Example Usage

#include <stdio.h>

int main(void) {
int limit = 3;
loop_start:
int counter = 0; // declaration allowed directly after label
counter++;
printf(”Counter: %d\n”, counter);
if (counter < limit) goto loop_start;
return 0;
}

2.12.4 Notes for Practitioners


• Labels still require unique identifiers within a function.

• Declarations immediately after labels follow normal scope and lifetime rules.

• Helps maintain compact and maintainable low-level code, avoiding unnecessary


blocks.

By permitting labels with declarations, C23 enhances flexibility and readability in


control-flow-heavy code, making it safer and more maintainable for systems and
embedded programmers.
Chapter 3

Preprocessor and Compilation Features

3.1 New Directives (#elifdef, #elifndef, #warning, #embed)


C23 introduces several new preprocessor directives that simplify conditional
compilation, debugging, and embedding external resources. These updates improve code
clarity, maintainability, and cross-platform support.

3.1.1 #elifdef and #elifndef


• Combines #elif with #ifdef / #ifndef for shorter conditional expressions.

#ifdef FEATURE_A
// Code for FEATURE_A
#elifdef FEATURE_B
// Code for FEATURE_B
#elifndef FEATURE_C
// Code if FEATURE_C is not defined
#endif

59
60

• Reduces nested preprocessor blocks, making code more readable.

• Functions identically to equivalent #elif defined(...) or #elif !defined(...) but is


syntactically cleaner.

3.1.2 #warning
• Emits a compiler warning with a custom message during preprocessing.

• Useful for deprecated features, missing configuration, or reminders.

#warning ”This feature will be removed in future versions”

• Does not stop compilation, unlike #error.

3.1.3 #embed
• Allows embedding external files or resources directly into source code.

• Useful for binary blobs, firmware data, or configuration files.

#embed ”config.bin” as const unsigned char config_data[];

• Simplifies resource management, avoiding manual conversion or external file


handling.
61

3.1.3.1 Key Advantages

1. Cleaner Conditional Compilation

• Reduces verbosity and complexity in multi-feature builds.

2. Better Build-Time Diagnostics

• #warning helps communicate important information during compilation.

3. Direct Resource Embedding

• Facilitates embedding binaries and data directly in executables for embedded


and systems programming.

3.1.3.2 Example Usage

#include <stdio.h>

#ifdef FEATURE_X
#warning ”Using FEATURE_X; consider updating”
#endif

#embed ”firmware.bin” as const unsigned char fw[];

int main(void) {
printf(”Firmware size: %zu bytes\n”, sizeof(fw));
return 0;
}
62

3.1.3.3 Notes for Practitioners

• #elifdef / #elifndef improve conditional compilation readability.

• #warning is ideal for temporary alerts or deprecation notices.

• #embed is highly useful in embedded systems and low-level firmware


development, where external resources need to be part of the binary.

C23’s new preprocessor directives enhance flexibility, clarity, and efficiency, aligning
the language with modern development practices for professional and system-level
programming.
63

3.2 Feature-Test Macros (__STDC_IEC_60559_BFP__, etc.)


C23 introduces feature-test macros to enable compile-time detection of optional
language and library features, allowing developers to write portable and standards-
compliant code.

3.2.1 Key Macros and Their Purpose


1. __STDC_IEC_60559_BFP__

• Indicates support for IEEE-754 binary floating-point arithmetic and required


mathematical functions.
• Supersedes the older __STDC_IEC_559__ macro.

2. __STDC_IEC_60559_DFP__

• Signals support for IEEE-754 decimal floating-point arithmetic.

3. __STDC_IEC_60559_COMPLEX__

• Confirms support for IEEE-754 complex arithmetic.


• Replaces __STDC_IEC_559_COMPLEX__.

3.2.2 Usage Example

#include <stdio.h>

#if defined(__STDC_IEC_60559_BFP__)
#define HAS_BINARY_FP 1
64

#else
#define HAS_BINARY_FP 0
#endif

int main(void) {
printf(”Binary floating-point supported: %d\n”, HAS_BINARY_FP);
return 0;
}

• These macros allow conditional compilation depending on the platform’s floating-


point capabilities.

• Enables writing code that adapts safely to the underlying hardware and library
support.

3.2.2.1 Key Advantages

1. Portable Code

• Write features dependent on IEEE-754 compliance without hardcoding


assumptions.

2. Improved Compatibility

• Facilitates cross-platform development, especially in scientific and embedded


applications.

3. Compile-Time Safety

• Detects unsupported features at compile time, reducing runtime errors.


65

3.2.2.2 Notes for Practitioners

• Essential for high-precision arithmetic, financial calculations, and scientific


computing.

• Can be combined with new C23 floating-point functions to create robust


numerical code.

• Provides a standardized, compiler-independent way to check for optional C


features.

C23’s feature-test macros enhance portability, safety, and clarity, enabling professional
developers to write reliable, cross-platform C code.
66

3.3 Pragmas for Rounding Direction (STDC FENV_ROUND,


STDC FENV_DEC_ROUND)
C23 introduces standardized pragmas to control the rounding direction of floating-
point operations, both for binary and decimal arithmetic. This enables precise numeric
control and improved predictability in computations.

3.3.1 Key Pragmas


1. STDC FENV_ROUND

• Defines the rounding mode for binary floating-point operations.

• Rounding modes include:

– FE_TONEAREST – Round to nearest


– FE_DOWNWARD – Round toward negative infinity
– FE_UPWARD – Round toward positive infinity
– FE_TOWARDZERO – Round toward zero

2. STDC FENV_DEC_ROUND

• Controls rounding for decimal floating-point arithmetic (_Decimal32,


_Decimal64, _Decimal128).

• Supports similar rounding modes as binary floating-point.

3.3.2 Syntax Example


67

#pragma STDC FENV_ROUND FE_TONEAREST

#include <stdio.h>
#include <fenv.h>
#include <math.h>

int main(void) {
double x = 2.7;
double y = 2.5;

printf(”Round 2.7: %.1f\n”, nearbyint(x)); // Rounds according to FE_TONEAREST


printf(”Round 2.5: %.1f\n”, nearbyint(y));

return 0;
}

3.3.2.1 Key Advantages

1. Predictable Numerical Behavior

• Ensures consistent results across different platforms and compilers.

2. Critical for Embedded and Scientific Computing

• Enables deterministic rounding, important in financial, physics, and DSP


applications.

3. Seamless Decimal and Binary Support

• Works with both binary floats and C23 decimal types (_Decimal32,
_Decimal64, _Decimal128).
68

3.3.2.2 Notes for Practitioners

• Use these pragmas when precise rounding control is essential.

• Combine with C23 floating-point math functions for robust, standard-compliant


computations.

• Provides compile-time control over rounding behavior, enhancing portability and


correctness.

C23’s rounding-direction pragmas provide system and embedded programmers with


fine-grained control over numeric computations, ensuring precision, predictability, and
reliability in professional applications.
Chapter 4

Standard Library Enhancements

4.1 New Headers (<stdbit.h>, <stdckdint.h>)


C23 introduces two new standard headers to extend the capabilities of the C library,
providing modern, type-safe, and low-level utilities for professional programming.

4.1.1 <stdbit.h>
• Provides bit manipulation functions for integers, improving clarity and reducing
error-prone manual bit operations.

• Functions include count leading zeros, count trailing zeros, population count, bit
rotation, and more.

#include <stdio.h>
#include <stdbit.h>

int main(void) {

69
70

unsigned int x = 0b101010;


printf(”Leading zeros: %d\n”, clz(x));
printf(”Population count: %d\n”, popcount(x));
return 0;
}

Advantages:

• Simplifies bit-level operations for systems and embedded programming.

• Enables portable, compiler-independent code for low-level tasks.

4.1.2 <stdckdint.h>
• Provides checked integer arithmetic to detect overflow and underflow.

• Functions return a status flag along with the computed value, preventing silent
errors.

#include <stdio.h>
#include <stdckdint.h>

int main(void) {
int result;
if (ckd_add_int(&result, INT_MAX, 1)) {
printf(”Overflow detected!\n”);
} else {
printf(”Sum: %d\n”, result);
}
return 0;
}
71

Advantages:

• Improves safety in arithmetic operations.

• Essential for high-reliability, embedded, and financial applications.

4.1.2.1 Notes for Practitioners

• Both headers are lightweight, standardized, and portable.

• <stdbit.h> focuses on bit manipulation, <stdckdint.h> on safe arithmetic.

• Together, they provide modern tools for robust system-level programming.

C23’s new headers enhance the standard library by offering modern, safe, and efficient
utilities, aligning C with contemporary system and embedded development practices.
72

4.2 Extended Math Functions (Binary & Decimal Floating-Point)


C23 extends the math library with new functions for both binary and decimal floating-
point types, providing precise, high-performance arithmetic for scientific, financial, and
embedded applications.

4.2.1 Binary Floating-Point Extensions


• Functions for IEEE-754 binary floats (float, double, long double) include:

– exp2, expm1, log1p, cbrt, hypot variants


– fma enhancements and _n suffixed versions for precision

#include <math.h>
#include <stdio.h>

int main(void) {
double x = 2.5;
printf(”expm1(%.2f) = %.5f\n”, x, expm1(x));
printf(”cbrt(%.2f) = %.5f\n”, x, cbrt(x));
return 0;
}

4.2.2 Decimal Floating-Point Extensions


• Functions for decimal types (_Decimal32, _Decimal64, _Decimal128) include:

– quantizedN(), samequantumdN(), quantumdN()


– llquantexpdN(), encode/decode dN/bindN()
73

• Enable precise decimal computations suitable for financial and scientific domains.

#include <math.h>
#include <stdio.h>
#include <decimal/decimal.h> // Example header

_Decimal64 a = 123.45df64;
_Decimal64 b = 0.05df64;
printf(”quantized: %.2Df\n”, quantized64(a + b));

4.2.2.1 Key Advantages

1. High Precision Arithmetic

• Supports IEEE-754 compliance for both binary and decimal operations.

2. Consistency Across Platforms

• Ensures portable and reproducible results, critical for financial and scientific
applications.

3. Enhanced Performance

• Optimized for modern CPUs, enabling fast and accurate calculations.

4. Full C23 Integration

• Works seamlessly with new types like _Decimal32/64/128 and _BitInt.


74

4.2.2.2 Notes for Practitioners

• Use decimal functions for exact fractional arithmetic, avoiding rounding errors
common in binary floats.

• Binary extensions improve standard math operations, including advanced


transcendental and geometric functions.

• Ideal for embedded, systems, and high-reliability applications where precision and
reproducibility are critical.

C23’s extended math library equips programmers with modern, precise, and portable
tools for high-accuracy computation across both binary and decimal floating-point
domains.
75

4.3 UTF-8 Support (char8_t, mbrtoc8(), c8rtomb())


C23 introduces native UTF-8 support to the C standard library, improving text
handling, portability, and interoperability in modern applications.

4.3.1 char8_t Type


• Represents a single UTF-8 code unit.

• Distinct from char or unsigned char, ensuring type safety in UTF-8 string
operations.

char8_t u8_char = u8'A'; // UTF-8 character

4.3.2 mbrtoc8()
• Converts multi-byte sequences to char8_t.

• Facilitates parsing UTF-8 text from external sources.

#include <uchar.h>
#include <stdio.h>

char8_t c;
const char *mb = ”A”;
mbrtoc8(&c, mb, 1, NULL);
printf(”UTF-8 char: %c\n”, c);
76

4.3.3 c8rtomb()
• Converts a char8_t value back to a multi-byte sequence.

• Useful for writing UTF-8 data to files or network streams.

char mb[4];
c8rtomb(mb, u8'A', NULL);
printf(”Multi-byte: %s\n”, mb);

4.3.3.1 Key Advantages

1. Type-Safe UTF-8 Handling

• Avoids misuse of char arrays for UTF-8 text.

2. Standardized Conversions

• Simplifies encoding and decoding between multi-byte sequences and UTF-8


code units.

3. Portability

• Works across all platforms with C23 compliance, facilitating


internationalized software.

4. Seamless Library Integration

• Compatible with new C23 features such as atomic types (atomic_char8_t)


and safe string operations.
77

4.3.3.2 Notes for Practitioners

• Use char8_t for all UTF-8 string data to prevent type mismatches.

• mbrtoc8() and c8rtomb() enable reliable conversions between UTF-8 and multi-
byte encodings.

• Essential for embedded systems, cross-platform applications, and modern system-


level software requiring Unicode support.

C23’s UTF-8 support standardizes modern text handling, offering safety, portability,
and clarity for professional C programmers dealing with internationalized and multi-
byte text data.
78

4.4 Explicit Memory Clearing (memset_explicit())


C23 introduces memset_explicit(), a secure variant of memset() designed to guarantee
that sensitive data is cleared from memory, preventing compilers from optimizing away
the clearing.

4.4.1 Purpose
• Protects cryptographic keys, passwords, and sensitive buffers.

• Ensures memory is overwritten even when compilers attempt dead-store


elimination.

4.4.2 Syntax

void *memset_explicit(void *s, int c, size_t n);

• s – Pointer to the memory buffer.

• c – Byte value to set (usually 0).

• n – Number of bytes to clear.

4.4.3 Example Usage

#include <string.h>
#include <stdio.h>

int main(void) {
79

char secret[32] = ”SuperSecretPassword”;

printf(”Before clear: %s\n”, secret);


memset_explicit(secret, 0, sizeof(secret));
printf(”After clear: %s\n”, secret); // Memory reliably cleared
return 0;
}

4.4.3.1 Key Advantages

1. Security

• Prevents sensitive data from lingering in memory.

2. Compiler Safety

• Unlike memset(), cannot be optimized away by aggressive compiler


optimizations.

3. Standardized Approach

• Provides a portable, C23-compliant method for memory sanitization.

4.4.3.2 Notes for Practitioners

• Use memset_explicit() for passwords, cryptographic keys, and secure buffers.

• Works in all modern C23-compliant compilers.

• Complements other safe memory handling techniques in C23 for robust, secure
applications.
80

C23’s memset_explicit() provides a standard, reliable mechanism for securely erasing


memory, essential for systems, embedded, and security-critical software.
81

4.5 New POSIX-Like Functions (memccpy(), strdup(),


gmtime_r(), localtime_r())
C23 standardizes several POSIX-inspired functions to improve memory handling,
string duplication, and thread-safe time operations, making system and embedded
programming more portable and robust.

4.5.1 memccpy()
• Copies bytes from source to destination up to a specified character, stopping when
the character is found.

• Returns a pointer to the next byte in the destination or NULL if the character
isn’t found.

#include <string.h>
#include <stdio.h>

int main(void) {
char src[] = ”Hello, C23!”;
char dst[20];
memccpy(dst, src, ',', sizeof(src));
printf(”Copied: %s\n”, dst);
return 0;
}

Use Case: Efficient partial memory copying for buffers and message parsing.

4.5.2 strdup()
• Duplicates a string, allocating memory dynamically.
82

• Returns a pointer to the newly allocated string.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
char *s = strdup(”C23 is modern”);
printf(”%s\n”, s);
free(s); // Must free allocated memory
return 0;
}

Use Case: Simplifies safe string duplication in memory-managed operations.

4.5.3 gmtime_r() and localtime_r()


• Thread-safe versions of gmtime() and localtime().

• Store results in user-provided buffers, avoiding static data races.

#include <time.h>
#include <stdio.h>

int main(void) {
time_t t = time(NULL);
struct tm tm_buf;

gmtime_r(&t, &tm_buf);
printf(”UTC Year: %d\n”, tm_buf.tm_year + 1900);
83

localtime_r(&t, &tm_buf);
printf(”Local Year: %d\n”, tm_buf.tm_year + 1900);

return 0;
}

Use Case: Essential for multithreaded applications and embedded systems requiring
safe time conversions.

4.5.3.1 Key Advantages

1. Thread Safety

• gmtime_r() and localtime_r() prevent race conditions in multithreaded


programs.

2. Portability

• Provides standardized, cross-platform implementations of POSIX-like


functionality.

3. Convenience and Safety

• memccpy() and strdup() reduce boilerplate code and prevent common


memory-handling errors.

C23’s POSIX-like function enhancements bring robust, thread-safe, and convenient


APIs to the standard library, facilitating modern system-level and embedded C
programming.
84

4.6 Extended strftime(), fscanf(), fprintf()


C23 enhances several standard I/O and time formatting functions, adding new length
modifiers, conversion specifiers, and extended support for integers and decimal types,
improving precision, readability, and compatibility.

4.6.1 strftime() and wcsftime() Extensions

• New format specifiers for _Decimal32/64/128 and extended numeric


representations.

• Provides more precise formatting for time and numeric data in both narrow and
wide strings.

#include <stdio.h>
#include <time.h>

int main(void) {
char buffer[64];
time_t t = time(NULL);
struct tm tm_info = *localtime(&t);

strftime(buffer, sizeof(buffer), ”%Y-%m-%d %H:%M:%S”, &tm_info);


printf(”Current time: %s\n”, buffer);
return 0;
}

Benefit: Improves time formatting flexibility, especially for internationalized


applications.
85

4.6.2 fscanf() and fprintf() Extensions


• New length modifiers:

– wN and wfN for [u]intN_t and [u]int_fastN_t


– H, D, DD for _Decimal32, _Decimal64, _Decimal128

• New conversion specifier:

– b for unsigned integer types in binary format

#include <stdio.h>
#include <stdint.h>

uint32_t value = 42;


fprintf(stdout, ”%b\n”, value); // prints: 101010

Benefit: Allows direct binary output, precise handling of modern integer and decimal
types, and cleaner formatted I/O.

4.6.2.1 Key Advantages

1. Enhanced Numeric I/O

• Supports C23 integer and decimal types, improving read/write precision.

2. Binary Output Support

• Facilitates debugging, embedded systems, and low-level applications


requiring binary representation.

3. Extended Time and Localization Support


86

• Makes strftime/wcsftime more flexible for internationalization and complex


time formatting.

4.6.2.2 Notes for Practitioners

• Use new modifiers for consistent I/O across binary, integer, and decimal types.

• Extended specifiers reduce manual conversion and error-prone formatting.

• Ideal for professional system-level and embedded programming where precision


and portability matter.

C23’s extended I/O and formatting functions bring modern precision and flexibility to
C’s standard library, enhancing readability, portability, and developer efficiency.
87

4.7 Formatting Updates – New Specifiers (b, H, D, DD, wN)


C23 introduces new format specifiers to improve I/O precision and readability for
modern integer and decimal types in printf/scanf family functions. These additions
simplify binary output, decimal arithmetic, and fixed-width integer handling.

4.7.1 b – Binary Conversion Specifier


• Allows printing unsigned integers in binary format.

• Simplifies debugging and embedded system logging.

#include <stdio.h>
#include <stdint.h>

uint8_t value = 42;


printf(”Binary: %b\n”, value); // Output: 101010

4.7.2 H, D, DD – Decimal Floating-Point Types


• H → _Decimal32

• D → _Decimal64

• DD → _Decimal128

• Enables direct formatting of decimal floating-point values in I/O functions.


88

#include <stdio.h>
#include <decimal/decimal.h>

_Decimal64 d = 123.45df64;
printf(”Decimal64: %D\n”, d);

4.7.3 wN and wfN – Width-Specific Integer Modifiers


• wN → [u]intN_t

• wfN → [u]int_fastN_t

• Provides portable, type-safe formatting for fixed-width integers.

#include <stdio.h>
#include <stdint.h>

uint16_t u16 = 65535;


printf(”Fixed-width: %w16\n”, u16);

4.7.3.1 Key Advantages

1. Binary Support

• Native %b specifier simplifies low-level debugging and embedded output.

2. Decimal Floating-Point Integration

• %H, %D, %DD enable direct use of new C23 decimal types in formatted
I/O.
89

3. Portable Fixed-Width Integers

• wN and wfN provide consistent behavior across platforms.

4. Cleaner and Safer Code

• Reduces manual conversions and potential errors when formatting modern


C23 types.

4.7.3.2 Notes for Practitioners

• Combine with new C23 library types for consistent, portable I/O.

• Useful in embedded, financial, and scientific applications requiring precise output.

• Enhances readability, maintainability, and debugging efficiency.

C23’s formatting updates make the standard library more expressive, type-safe, and
aligned with modern programming needs.
90

4.8 New Library Test Macros


(__STDC_VERSION_FENV_H__, etc.)
C23 introduces library version-test macros to allow compile-time detection of library
features, enabling portable and conditional programming across different platforms and
C implementations.

4.8.1 Purpose
• Verify support for specific C23 library headers and features.

• Enable feature-dependent code paths for portability and modern compliance.

4.8.2 Key Macros

Macro Purpose
__STDC_VERSION_FENV_H__ Indicates <fenv.h> compliance and
rounding/primitives support
__STDC_VERSION_MATH_H__Confirms <math.h> functions and extensions
are available
__STDC_VERSION_STDINT_H__
Confirms <stdint.h> and fixed-width integers
__STDC_VERSION_STDLIB_H__
Confirms <stdlib.h> compliance with C23
enhancements
__STDC_VERSION_TGMATH_H__
Confirms <tgmath.h> type-generic math
functions
__STDC_VERSION_TIME_H__ Confirms <time.h> time and formatting
functions
91

Macro Purpose
__STDC_VERSION_STDCKDINT_H__
Confirms <stdckdint.h> checked integer
arithmetic
__STDC_VERSION_STDBIT_H__
Confirms <stdbit.h> bit manipulation
utilities

4.8.3 Example Usage

#include <stdio.h>

#ifdef __STDC_VERSION_STDBIT_H__
#include <stdbit.h>
#endif

int main(void) {
#ifdef __STDC_VERSION_STDBIT_H__
printf(”Bit manipulation header is supported.\n”);
#else
printf(”Fallback: custom bit functions required.\n”);
#endif
return 0;
}

4.8.3.1 Key Advantages

1. Portability

• Write code that adapts to compiler/library support without runtime checks.

2. Future-Proofing
92

• Prepare for incremental adoption of new C23 features.

3. Conditional Compilation

• Reduces compilation errors when targeting multiple platforms or older


libraries.

4.8.3.2 Notes for Practitioners

• Use these macros in headers or library wrappers to detect C23 capabilities.

• Essential for professional, cross-platform system and embedded programming.

• Simplifies feature-aware coding and enhances maintainability.

C23’s library version-test macros empower developers to write robust, portable, and
future-proof C code that adapts dynamically to the available standard library features.
Chapter 5

Removed & Deprecated Features

5.1 Removed Features


C23 takes a decisive step toward modernizing the C language by removing outdated
and unsafe constructs. These removals simplify the language, reduce ambiguities,
and improve portability and maintainability for professional systems and embedded
programmers.

5.1.1 Old-Style Function Declarations (K&R Style)


What was removed:

• The K&R style (pre-C89) function declarations, where parameter types were
declared separately from the function header.

• Example (removed in C23):

93
94

int sum(a, b)
int a;
int b;
{
return a + b;
}

Modern replacement:

int sum(int a, int b) {


return a + b;
}

Implications:

1. Type Safety: K&R style lacked type checking for function parameters. Removing
it ensures all functions declare types explicitly.

2. Readability & Maintainability: Modern prototypes clearly indicate parameter


types, helping developers understand the interface quickly.

3. Tooling Support: Static analyzers, compilers, and IDEs can better detect errors in
type usage.

Best Practice: Always use modern prototypes in headers and implementations. Avoid
legacy declarations to maintain future-proof code.

5.1.2 Non–Two’s Complement Integers


What was removed:

• Previously, C allowed platforms to implement signed integers using ones’


complement or sign-magnitude representations.
95

Modern requirement in C23:

• All signed integers must use two’s complement representation.

Implications:

1. Predictable Arithmetic: Two’s complement guarantees that addition, subtraction,


and negation behave consistently across platforms.

2. Bitwise Operations Reliability: Bit shifts, masks, and bitwise negation now
produce uniform results, which is essential for embedded systems, low-level
programming, and cryptographic code.

3. Portability: Code written for one compiler or architecture will behave identically
on another.

Example:

int a = -5;
int b = a >> 1; // Predictable arithmetic right shift in two's complement

Best Practice: Always assume two’s complement integers for calculations and bitwise
logic.

5.1.3 Mixed Wide and Narrow String Literal Concatenation


What was removed:

• Concatenating wide string literals (L”...”) with narrow string literals (”...”) is no
longer valid.

Example (removed):
96

L”Wide ” ”narrow”; // Invalid in C23

Rationale:

1. Consistency: Mixing narrow and wide strings caused unexpected type mismatches
and potential runtime errors.

2. Unicode Safety: Ensures wide strings remain wide and narrow strings remain
narrow, simplifying internationalization and encoding correctness.

3. Compiler Simplicity: Reduces ambiguity in constant expression evaluation and


storage allocation.

Best Practice: Keep wide and narrow literals separate. Use u8””, u””, or U”” literals
consistently.

5.1.4 realloc(0) Behavior Undefined


What was removed:

• In prior standards, calling realloc(ptr, 0) could return a null pointer or a valid


pointer, leading to undefined or implementation-dependent behavior.

Modern requirement in C23:

• Behavior is now explicitly undefined, making it the programmer’s responsibility to


handle zero-size reallocations correctly.

Example:
97

char *ptr = malloc(10);


ptr = realloc(ptr, 0); // Undefined behavior in C23
free(ptr); // Correct approach

Implications:

1. Code Safety: Forces explicit handling of memory allocation and deallocation,


reducing silent errors.

2. Predictable Behavior: Eliminates platform-specific quirks that previously caused


subtle bugs in production systems.

3. Security: Prevents accidental buffer misuse or memory leaks due to inconsistent


realloc behavior.

Best Practice:

• Check for zero-size allocations before calling realloc().

• Use free() explicitly if size is zero or allocate a minimal valid size.

5.1.4.1 Overall Advantages of C23 Removals

1. Simplified Language Rules: By removing old and ambiguous constructs, C23


provides a cleaner and more predictable core language.

2. Improved Portability: Code now behaves consistently across compilers and


platforms, including embedded and high-performance systems.

3. Enhanced Safety and Maintainability: Legacy features that caused errors, type
confusion, or unsafe operations are gone.

4. Professional Standards Compliance: Encourages modern coding practices,


preparing developers for future C extensions and system-level programming.
98

5.1.4.2 Notes for Practitioners

• Review legacy code to update old-style declarations and remove non-portable


constructs.

• Ensure all string literals, memory operations, and integer manipulations comply
with C23 rules.

• These removals reinforce robust, maintainable, and secure coding practices for
professional C programmers, especially in systems, embedded, and security-critical
applications.

C23’s removal of outdated and unsafe features strengthens the language, focusing
on clarity, consistency, and modern software engineering principles, while retaining
the efficiency and low-level control that makes C the language of choice for system
programmers.
99

5.2 Deprecated Headers (<stdnoreturn.h>, <stdalign.h>,


<stdbool.h>)
C23 marks several previously standard headers as deprecated, reflecting the language’s
shift toward keyword-based and modern constructs. Deprecated headers remain
available for backward compatibility but new code should avoid them.

5.2.1 <stdnoreturn.h>
Purpose (pre-C23):

• Provided the _Noreturn macro for declaring functions that do not return.

#include <stdnoreturn.h>

noreturn void fatal_error(void);

C23 Update:

• _Noreturn is now a keyword, making the header unnecessary.

void fatal_error(void) _Noreturn;

Implications:

1. Cleaner Syntax: No need to include a separate header.

2. Compiler Enforcement: Keywords are more consistently recognized than macros.

3. Backwards Compatibility: <stdnoreturn.h> still exists, but using it is


discouraged.
100

5.2.2 <stdalign.h>
Purpose (pre-C23):

• Provided alignas and alignof macros for controlling and querying memory
alignment.

#include <stdalign.h>

alignas(16) int data[4];

C23 Update:

• alignas and alignof are now keywords, replacing the need for the header.

alignas(16) int data[4]; // Same effect, no header needed

Implications:

1. Modern Alignment Control: Keywords offer native compiler support, improving


performance and clarity.

2. Simplified Headers: Less reliance on auxiliary headers.

3. Portability: Consistent across all C23-compliant compilers.

5.2.3 <stdbool.h>
Purpose (pre-C23):

• Introduced the bool type and true/false macros for Boolean logic in C.
101

#include <stdbool.h>

bool flag = true;

C23 Update:

• bool, true, and false are keywords, removing the need for <stdbool.h>.

bool flag = true; // Header no longer required

Implications:

1. Cleaner Code: Boolean types are native to the language, avoiding macro-based
definitions.

2. Safety: Eliminates potential macro conflicts with other libraries or user code.

3. Consistency: Aligns C with modern programming languages that support native


Boolean types.

5.2.3.1 Key Advantages of Deprecation

1. Simplified Syntax and Readability

• Replacing macros with keywords improves code clarity.

2. Native Compiler Support

• Keywords are more robust and less error-prone than header-based macros.

3. Encourages Modern Practices


102

• Developers are nudged toward clean, maintainable, and standard-compliant


C23 code.

4. Backward Compatibility Maintained

• Headers still exist but are officially discouraged for new code.

5.2.3.2 Best Practices for Practitioners

• Avoid <stdnoreturn.h>, <stdalign.h>, and <stdbool.h> in new projects.

• Use keywords _Noreturn, alignas, alignof, bool, true, and false instead.

• Maintain legacy code using these headers only if updating is impractical.

• Combine with other C23 features (e.g., _BitInt, _Decimal64) to leverage the
modernized type system.

C23’s header deprecations represent a move toward native language features, reducing
dependency on auxiliary headers and fostering cleaner, more maintainable, and forward-
compatible code for professional programmers.
103

5.3 Deprecated Macros (__STDC_IEC_559__,


DECIMAL_DIG, INFINITY, NAN)
C23 officially deprecates several legacy macros that were historically used for floating-
point behavior and numeric limits, in favor of type-specific or keyword-based features.
These changes improve clarity, portability, and safety in modern C programming.

5.3.1 __STDC_IEC_559__ and __STDC_IEC_559_COMPLEX__


Purpose (pre-C23):

• Indicated that the implementation conforms to IEEE-754 binary floating-point


arithmetic and supports required math functions.

• Separate macro for complex arithmetic: __STDC_IEC_559_COMPLEX__.

C23 Update:

• Superseded by new macros:

– __STDC_IEC_60559_BFP__ → binary floating-point


– __STDC_IEC_60559_COMPLEX__ → complex floating-point

Implications:

1. More precise naming: Explicitly indicates IEEE-754 compliance.

2. Portability: Reduces confusion between older macros and optional features.

3. Feature detection: Helps programmers write conditional code based on precise


floating-point support.
104

#ifdef __STDC_IEC_60559_BFP__
// safe to use binary floating-point functions
#endif

5.3.2 DECIMAL_DIG
Purpose (pre-C23):

• Provided a generic maximum decimal digits of precision for floating-point types.

C23 Update:

• Deprecated in favor of type-specific macros:

– FLT_DECIMAL_DIG, DBL_DECIMAL_DIG,
_Decimal64_DECIMAL_DIG, etc.

Implications:

1. Type-specific clarity: Each floating-point type now has a dedicated precision


macro.

2. Avoids ambiguity: Eliminates confusion for mixed-type calculations.

#include <float.h>
printf(”Max digits for double: %d\n”, DBL_DECIMAL_DIG);
105

5.3.3 INFINITY and NAN


Purpose (pre-C23):

• Represented infinity and Not-a-Number values for floating-point calculations.

C23 Update:

• Standardized via <float.h> constants and <math.h> functions.

• Legacy macros remain for compatibility but are discouraged in favor of


HUGE_VAL, HUGE_VALF, HUGE_VALL or std::numeric_limits in C++.

Implications:

1. Consistent naming across types: Separate constants for float, double, and long
double.

2. Improved precision and portability: Reduces platform-dependent behavior.

#include <math.h>
double x = HUGE_VAL; // replaces legacy INFINITY macro

5.3.3.1 Key Advantages of Deprecation

1. Precision and Type Safety

• Type-specific macros ensure correctness in numeric computations.

2. Improved Portability
106

• Modern macros clearly indicate floating-point type and representation,


simplifying cross-platform development.

3. Cleaner Code

• Encourages the use of modern constants and library functions instead of


legacy macros.

4. Forward Compatibility

• Prepares codebases for future C standards and advanced numeric types,


including _Decimal32, _Decimal64, and _Decimal128.

5.3.3.2 Best Practices for Practitioners

• Replace DECIMAL_DIG with type-specific macros like FLT_DECIMAL_DIG or


_Decimal64_DECIMAL_DIG.

• Use __STDC_IEC_60559_BFP__ and __STDC_IEC_60559_COMPLEX__


for floating-point feature checks.

• Prefer HUGE_VAL/HUGE_VALF/HUGE_VALL over INFINITY and NAN in


modern C23 code.

• Audit legacy code for deprecated macros to ensure portable, maintainable, and
precise numeric computations.

C23’s deprecation of these macros reflects a shift toward explicit, type-safe, and
portable floating-point programming, aligning the language with modern system
programming and scientific computing needs.
107

5.4 Deprecated Features (_Noreturn, asctime(), ctime())


C23 formally deprecates several legacy function specifiers and time functions that
are either superseded by keywords or safer alternatives. Deprecation ensures modern,
maintainable, and portable code while retaining backward compatibility for legacy
systems.

5.4.1 _Noreturn Function Specifier


Purpose (pre-C23):

• _Noreturn was used to declare functions that do not return, typically for error
handling or program termination.

_Noreturn void fatal_error(void);

C23 Update:

• _Noreturn is now deprecated in favor of the noreturn keyword.

• Modern syntax:

void fatal_error(void) noreturn;

Implications:

1. Cleaner Syntax: Keywords integrate directly into the language, avoiding macro or
header dependencies.

2. Compiler Consistency: Ensures uniform compile-time checks across platforms.


108

3. Portability: Reduces reliance on <stdnoreturn.h> and legacy macros.

Best Practice: Use the noreturn keyword in all new code, reserving _Noreturn only for
legacy compatibility.

5.4.2 asctime() and ctime() Functions


Purpose (pre-C23):

• Provided simple string representations of calendar time (struct tm) for logging
and display.

#include <time.h>

time_t t = time(NULL);
printf(”%s”, asctime(localtime(&t)));
printf(”%s”, ctime(&t));

C23 Update:

• These functions are deprecated due to:

1. Thread safety issues: Both return pointers to static buffers, causing data
races in multi-threaded code.
2. Limited formatting flexibility: Developers cannot specify custom output
formats.

• Recommended replacements: thread-safe and format-controllable functions such


as:

– asctime_r() and ctime_r() (POSIX)


109

– strftime() for custom formatting

#include <time.h>

struct tm tstruct;
time_t t = time(NULL);
localtime_r(&t, &tstruct);

char buffer[64];
strftime(buffer, sizeof(buffer), ”%Y-%m-%d %H:%M:%S”, &tstruct);
printf(”%s\n”, buffer);

Implications:

1. Thread-Safe Programming: Avoids race conditions in multi-threaded applications.

2. Flexible Formatting: strftime() allows custom date/time formats, essential for


modern systems and embedded devices.

3. Future-Proof Code: Avoids reliance on unsafe static buffers, improving


maintainability.

5.4.2.1 Key Advantages of Deprecation

1. Improved Safety and Portability

• Using modern keywords and thread-safe functions eliminates legacy pitfalls.

2. Cleaner Code and Readability

• The language now supports explicit, self-describing constructs instead of


macro-based or static-buffer functions.
110

3. Alignment with Modern Standards

• Deprecation reflects C23’s philosophy of balancing backward compatibility


with modern needs.

5.4.2.2 Best Practices for Practitioners

• Replace _Noreturn with the noreturn keyword in all new functions that do not
return.

• Avoid asctime() and ctime(); prefer thread-safe variants (asctime_r, ctime_r) or


strftime() for formatted output.

• Review legacy code to eliminate deprecated specifiers and functions, ensuring C23
compliance.

• Combine these practices with modern memory, type, and floating-point features
introduced in C23 for robust, maintainable, and portable system code.

C23’s deprecation of _Noreturn and legacy time functions strengthens safety,


thread-awareness, and modern coding standards, empowering system and embedded
programmers to write reliable and future-proof code.
111

5.5 Guidance for Modern Replacements


C23 not only removes and deprecates outdated features, but also provides a clear path
for modern alternatives. This ensures that professional developers can transition legacy
code smoothly while embracing safer, more maintainable, and portable constructs.

5.5.1 Function Declarations


Legacy: Old-style (K&R) function declarations.

int sum(a, b)
int a; int b;
{ return a + b; }

Modern Replacement: Standardized prototypes with explicit parameter types.

int sum(int a, int b) {


return a + b;
}

Benefits:

• Type safety enforced at compile time.

• Easier to read, maintain, and integrate with modern toolchains.

5.5.2 _Noreturn Specifier


Legacy: _Noreturn macro or function specifier.
112

_Noreturn void fatal_error(void);

Modern Replacement: Use the noreturn keyword.

void fatal_error(void) noreturn;

Benefits:

• Eliminates dependency on <stdnoreturn.h>.

• Compiler checks are consistent across platforms.

5.5.3 Floating-Point Macros and Constants


Legacy: DECIMAL_DIG, INFINITY, NAN, __STDC_IEC_559__.
Modern Replacements:

• Use type-specific macros for precision: FLT_DECIMAL_DIG,


DBL_DECIMAL_DIG, _Decimal64_DECIMAL_DIG.

• Replace INFINITY and NAN with HUGE_VAL, HUGE_VALF, HUGE_VALL,


or <math.h> functions.

• Use feature-test macros like __STDC_IEC_60559_BFP__ for conditional


compilation.

Benefits:

• Precise, type-aware, and portable numeric operations.

• Ensures compatibility with IEEE-754 standards.


113

5.5.4 Alignment Keywords


Legacy: <stdalign.h> macros alignas, alignof.
Modern Replacement: Use language keywords.

alignas(16) int data[4];


size_t alignment = alignof(int);

Benefits:

• No header dependencies; compiler handles alignment directly.

• Consistent behavior across platforms and architectures.

5.5.5 Boolean Types


Legacy: <stdbool.h> macros bool, true, false.
Modern Replacement: Use keywords:

bool flag = true;

Benefits:

• Simplifies code and eliminates macro conflicts.

• Aligns with modern languages and coding standards.

5.5.6 Time Functions


Legacy: asctime(), ctime().
Modern Replacements:

• Use thread-safe variants (asctime_r, ctime_r).


114

• Use strftime() for custom formatting and thread safety.

Benefits:

• Eliminates static buffer issues in multi-threaded environments.

• Provides flexible date/time formatting.

5.5.7 Memory Functions


Legacy: Using realloc(0) or unsafe memory clearing functions.
Modern Replacements:

• Handle zero-size allocations explicitly.

• Use memset_explicit() for secure memory clearing.

Benefits:

• Prevents undefined behavior and potential security vulnerabilities.

5.5.8 General Guidance for Practitioners


1. Audit Legacy Code: Identify removed or deprecated features.

2. Apply Modern Replacements: Use keywords, type-specific macros, thread-safe


functions, and secure memory operations.

3. Prioritize Portability: Write code that behaves consistently across C23-compliant


compilers and architectures.

4. Combine with New Features: Integrate _BitInt, _Decimal32/64/128, u8 strings,


and other modern C23 features for robust system programming.
115

5.5.9 Conclusion
C23 encourages developers to replace legacy constructs with modern equivalents.
Adopting these replacements ensures:

• Cleaner, more readable code.

• Safer, thread-aware, and type-safe operations.

• Portability across platforms and architectures.

• Long-term maintainability for systems and embedded applications.

Following this guidance allows programmers to leverage the full power of C23, while
ensuring backward-compatible modernization of legacy C code.
Chapter 6

Practical Migration Guide

6.1 Updating Existing C17 Codebases to C23


Transitioning from C17 to C23 requires careful planning to leverage modern features,
maintain backward compatibility, and improve code safety and performance. This
section provides a step-by-step approach for professional programmers.

6.1.1 Assess the Current Codebase


Action Steps:

• Identify deprecated headers, macros, and functions: <stdbool.h>, <stdalign.h>,


_Noreturn, DECIMAL_DIG, asctime(), ctime(), etc.

• Locate old-style function declarations and non-standard integer representations.

• Audit memory handling patterns, e.g., realloc(0) or uninitialized buffers.

• Check thread safety for time functions and global/static data.

116
117

Goal: Understand the scope of necessary updates and potential compatibility issues.

6.1.2 Replace Deprecated Constructs

Headers:

• <stdbool.h> → use bool, true, false keywords

• <stdalign.h> → use alignas, alignof keywords

• <stdnoreturn.h> → use noreturn keyword

Function Specifiers and Macros:

• _Noreturn → noreturn

• DECIMAL_DIG, INFINITY, NAN → type-specific macros


(FLT_DECIMAL_DIG, HUGE_VAL)

• __STDC_IEC_559__ → __STDC_IEC_60559_BFP__

Functions:

• asctime() / ctime() → asctime_r(), ctime_r(), or strftime()

• realloc(0) → handle explicitly or use modern memory management patterns

• Use memset_explicit() for secure clearing of sensitive memory


118

6.1.3 Adopt New C23 Language Features


Numeric and Boolean Improvements:

• Replace legacy integers with _BitInt for bit-precise types.

• Introduce _Decimal32/64/128 for decimal arithmetic.

• Use u8 strings and character literals for UTF-8 support.

Assertions and Safety:

• Convert static_assert(condition, msg) to single-argument static assertions where


applicable.

• Use [[nodiscard]], [[deprecated]], [[maybe_unused]] attributes for compile-time


warnings and safety.

Preprocessor and Compilation:

• Replace legacy feature-test macros with __STDC_IEC_60559_BFP__,


__STDC_IEC_60559_DFP__, and others.

• Leverage new directives: #elifdef, #elifndef, #warning, #embed.

6.1.4 Update Standard Library Usage


New Headers and Functions:

• Include <stdbit.h> and <stdckdint.h> for bit operations and checked integer
types.

• Replace deprecated functions with POSIX-like or thread-safe variants:


119

– memccpy(), strdup(), strndup()


– gmtime_r(), localtime_r()

Floating-Point and Formatting:

• Adopt extended floating-point math functions (binary & decimal)

• Update printf/scanf specifiers: b, H, D, DD, wN

• Use new library test macros (__STDC_VERSION_FENV_H__, etc.) for


feature checks

6.1.5 Test and Validate


Steps:

1. Compile code with C23-compliant compiler using warnings and feature flags.

2. Check for deprecated feature warnings.

3. Run unit tests and regression tests to ensure behavior remains consistent.

4. Validate thread safety and numeric correctness, especially with new floating-point
and bit-precise types.

6.1.6 Plan Gradual Migration


• Start small: Update modules incrementally to avoid breaking large codebases.

• Maintain backward compatibility: Use preprocessor checks to support C17 and


C23 builds if necessary.

• Document changes: Record which deprecated features were replaced with modern
equivalents.
120

6.1.7 Key Takeaways


• C23 introduces powerful features while maintaining backward compatibility, but
careful migration is essential.

• Focus on keywords, thread safety, type precision, and modern library functions.

• Gradual updates, testing, and clear documentation ensure a smooth transition


from C17 to C23, improving maintainability, safety, and performance.
121

6.2 Handling Deprecated Features


C23 deprecates several headers, macros, specifiers, and functions to modernize the
language and improve safety, portability, and maintainability. Handling deprecated
features correctly is essential to avoid warnings, ensure future-proof code, and maintain
compatibility.

6.2.1 Identify Deprecated Features


Key Categories:

• Headers: <stdbool.h>, <stdalign.h>, <stdnoreturn.h>

• Macros: _Noreturn, DECIMAL_DIG, INFINITY, NAN, __STDC_IEC_559__

• Functions: asctime(), ctime()

• Others: Old-style function declarations, realloc(0), mixed wide string literal


concatenation

Action:

• Use compiler warnings and static analysis tools to detect usage of deprecated
features.

• Maintain a migration checklist to systematically replace them.

6.2.2 Replace Deprecated Headers and Macros


Headers:

• <stdbool.h> → use bool, true, false keywords


122

• <stdalign.h> → use alignas and alignof keywords

• <stdnoreturn.h> → use noreturn keyword

Macros:

• _Noreturn → noreturn keyword

• DECIMAL_DIG → type-specific macros (FLT_DECIMAL_DIG,


DBL_DECIMAL_DIG, _Decimal64_DECIMAL_DIG)

• INFINITY, NAN → HUGE_VAL, HUGE_VALF, HUGE_VALL

• __STDC_IEC_559__ → __STDC_IEC_60559_BFP__

Benefits:

• Reduces compiler warnings and ensures C23 compliance

• Improves readability and maintainability

• Aligns with modern system and embedded programming practices

6.2.3 Replace Deprecated Functions


Time Functions:

• asctime() / ctime() → use asctime_r() or ctime_r() for thread safety

• Prefer strftime() for custom formatting

Memory Functions:

• Avoid realloc(0); explicitly handle zero-size allocations


123

• Use memset_explicit() for secure memory clearing

Benefits:

• Prevents undefined behavior and data races

• Ensures thread-safe and secure code

• Improves portability across platforms

6.2.4 Refactor Old Function Declarations


Legacy:

int sum(a, b)
int a; int b;
{ return a + b; }

Modern Replacement:

int sum(int a, int b) {


return a + b;
}

Benefits:

• Enforces type safety

• Simplifies code readability and maintenance

• Compatible with modern compiler optimizations


124

6.2.5 Strategies for Safe Handling


1. Incremental Replacement: Update one module at a time to minimize disruption.

2. Conditional Compilation: Use feature-test macros to support both legacy and


modern code during transition.

3. Static Analysis: Employ tools to detect unsafe or deprecated patterns.

4. Documentation: Clearly log which features were replaced and what alternatives
were adopted.

6.2.6 Key Takeaways


• Handling deprecated features is not just about removing warnings; it is about
modernizing, securing, and future-proofing your codebase.

• C23 provides keywords, type-specific macros, thread-safe functions, and secure


memory operations to replace old constructs.

• Following a systematic approach ensures smooth migration while maximizing the


benefits of C23 for systems, embedded, and professional programming.
125

6.3 Ensuring Portability Across Compilers


Migrating to C23 requires careful attention to compiler differences to ensure that code
behaves consistently across platforms and toolchains. Portability is crucial for system-
level, embedded, and cross-platform applications.

6.3.1 Use Standard Feature-Test Macros


C23 introduces macros to detect supported features:

• __STDC_IEC_60559_BFP__ → IEEE-754 binary floating-point support

• __STDC_IEC_60559_DFP__ → IEEE-754 decimal floating-point support

• __STDC_IEC_60559_COMPLEX__ → IEEE-754 complex arithmetic

Guidelines:

• Use these macros to conditionally compile code depending on compiler


capabilities.

• Ensures that floating-point, decimal, and complex operations behave consistently.

6.3.2 Avoid Compiler-Specific Extensions


• Stick to standardized C23 features.

• Minimize or encapsulate vendor-specific keywords or pragmas.

• If compiler-specific optimizations are required, wrap them with conditional


compilation:
126

#ifdef _MSC_VER
// MSVC-specific code
#elif defined(__GNUC__)
// GCC-specific code
#endif

Benefits:

• Reduces porting effort across compilers

• Improves long-term maintainability

6.3.3 Test Across Multiple Compilers


• Compile code using major C23-compliant compilers (GCC, Clang, MSVC).

• Use warning flags to catch non-portable or deprecated constructs:

gcc -Wall -Wextra -pedantic -std=c23


clang -Weverything -std=c23

• Automate continuous integration with multi-compiler builds.

Benefits:

• Early detection of undefined behavior or compiler-specific assumptions

• Ensures consistent runtime behavior


127

6.3.4 Handle Platform-Specific Data Types


• Use fixed-width types: int32_t, uint64_t from <stdint.h> or <stdckdint.h>

• Prefer _BitInt(N) for bit-precise integers in portable code

• Avoid assumptions about data type sizes (int is not guaranteed to be 32 bits)

Benefits:

• Predictable memory layout and arithmetic behavior

• Essential for embedded and cross-platform systems

6.3.5 Standardize Floating-Point Behavior


• Use IEEE-754 macros and rounding pragmas to control floating-point operations:

• Use type-specific math functions (float, double, _Decimal64) to avoid compiler-


specific rounding or optimizations.

Benefits:

• Consistent numerical results across architectures

• Avoids subtle portability bugs in scientific or financial code


128

6.3.6 Document Compiler Assumptions


• Maintain a portability matrix listing compiler versions and supported C23
features.

• Clearly annotate conditional code blocks for future maintenance.

Benefits:

• Simplifies code audits and migration updates

• Ensures team members understand compiler constraints

6.3.7 Key Takeaways


• Portability requires feature detection, standardized types, and disciplined testing.

• C23 provides macros, fixed-width types, and floating-point controls to facilitate


portable development.

• Following these practices ensures robust, maintainable, and cross-compiler


compatible code for systems, embedded, and professional applications.
129

6.4 Differences from C++ Features


C23 introduces several features inspired by C++ (e.g., nullptr, attributes, static_assert)
while maintaining C’s procedural simplicity and backward compatibility. Understanding
these differences is essential for system programmers transitioning from C++ or writing
interoperable code.

6.4.1 nullptr Constant


• C23 introduces nullptr as a keyword representing a null pointer, similar to C++.

• Differences from C++:

– In C23, nullptr is strictly a pointer literal; it does not support overload


resolution like in C++.

– It simplifies pointer initialization and null checks without introducing C++’s


type system complexities.

Example:

int *ptr = nullptr; // valid in C23


if (ptr == nullptr) { /* check null */ }

6.4.2 Attributes ([[nodiscard]], [[deprecated]], etc.)


• Attributes provide compile-time hints about function usage, variable usage, or
behavior expectations.

• Differences from C++:


130

– Attributes in C23 are limited to a standardized subset, primarily for


warnings, optimizations, and code safety.

– No C23 equivalent exists for C++ templates or complex metaprogramming


attributes.

Examples:

[[nodiscard]] int compute(); // warn if return value is ignored


[[deprecated]] void old_func(); // warn on usage

6.4.3 static_assert Keyword


• C23 allows single-argument static_assert(condition).

• Difference from C++:

– C++ permits optional messages: static_assert(condition, ”message”).

– C23 encourages simpler, minimal assertions, consistent with C’s procedural


style.

6.4.4 Type Safety and Keywords


• Keywords like alignas, alignof, thread_local, true, false are now native in C23.

• Differences from C++:

– No support for overloaded operators or constructors/destructors

– No C++ namespace or class-based scoping; keywords operate in a flat


procedural scope
131

Example:

alignas(16) int buffer[4]; // valid in C23

6.4.5 Intent and Philosophy


• C23 aims to modernize C without adopting C++ object-oriented paradigms.

• Provides safer, clearer, and more portable code, while retaining:

– Procedural structure
– Manual memory management
– Direct system-level access

• Developers familiar with C++ features must remember that C23 features are
simplified and procedural, avoiding complex C++ constructs like templates,
multiple inheritance, or operator overloading.

6.4.6 Key Takeaways


• C23 borrows useful concepts from C++ for safety, readability, and expressiveness,
but retains C’s simplicity.

• Features like nullptr, attributes, and static_assert enhance code correctness and
modern compiler diagnostics.

• Understanding these differences is critical for professional system programmers


who aim to leverage C23 effectively without assuming full C++ semantics.
Chapter 7

Future of C Beyond C23

7.1 Potential Directions


While C23 modernizes the language with features like bit-precise integers, decimal
floating-point, attributes, and improved standard libraries, the future of C is expected
to focus on enhancing safety, tooling, and modern developer ergonomics without
sacrificing performance or low-level control.

7.1.1 Memory Safety Enhancements


• Goal: Reduce common runtime errors like buffer overflows, use-after-free, and
dangling pointers while maintaining manual memory control.

• Potential Approaches:

– Optional bounds-checked arrays or pointer types


– Safer APIs for dynamic allocation
– Compiler-assisted static and dynamic memory checks

132
133

Impact: Improves security-critical and embedded systems code without enforcing full
runtime overhead.

7.1.2 Tooling Improvements


• Goal: Enhance the developer experience with modern tools while retaining
compatibility with legacy codebases.

• Possible Directions:

– Advanced static analysis integrated with compilers for C23 features

– Improved debugging support for attributes and floating-point modes

– Automated refactoring and migration tools for C17 → C23 → future C


versions

Impact: Reduces manual error detection effort and accelerates safe adoption of new
features.

7.1.3 Optional Borrow-Checking or Ownership Semantics


• Inspired by languages like Rust, C could explore optional ownership and borrow-
checking annotations:

– Maintain manual memory control but allow compiler-assisted lifetime


verification

– Detect dangling references, double frees, and race conditions at compile time

Impact: Provides memory safety guarantees for critical systems without imposing strict
enforcement across all C code.
134

7.1.4 Other Potential Directions


• Enhanced Concurrency Support:

– Extensions for atomic operations, thread-local memory, and parallel


algorithms

• Standard Library Expansion:

– Additional secure string, UTF-8, and numeric manipulation utilities

• Formal Verification and Contracts:

– Integration of function contracts or pre/post-conditions for critical system


validation

7.1.5 Key Takeaways


• The evolution of C aims to balance low-level efficiency, backward compatibility,
and modern safety features.

• Future C developments may focus on memory safety, enhanced tooling, and


optional borrow-checking, providing developers with stronger guarantees while
retaining C’s performance and control.

• C23 is just the beginning, setting a foundation for more secure, portable, and
expressive C in the coming years.
135

7.2 Comparison with Rust, Go, and Modern Systems Languages


C23 modernizes the C language, but emerging systems programming languages such
as Rust and Go offer features that extend beyond traditional C. Understanding these
differences helps professional programmers evaluate trade-offs and adopt best practices
for performance, safety, and maintainability.

7.2.1 Memory Safety

Feature C23 Rust Go


Manual memory Yes No (ownership No (garbage
management system) collection)
Null pointer safety Yes (nullptr) Yes (Option types) Yes (nil checks)
Use-after-free prevention No Yes No
Bounds checking No Yes Yes (runtime)

Insight:

• C23 improves code safety with features like nullptr and secure functions such as
memset_explicit().

• Rust enforces memory safety at compile-time, preventing common runtime errors.

• Go provides runtime safety with garbage collection, simplifying memory


management at the cost of some performance overhead.

7.2.2 Concurrency and Parallelism


136

Feature C23 Rust Go


Thread-local storage Yes Yes Yes (goroutines)
(thread_local)
Atomic operations Yes Yes Yes
Safe concurrency No Yes (borrow-checker No (runtime
ensures no data managed)
races)

Insight:

• C23 adds primitives for multi-threading and atomic operations.

• Rust ensures compile-time race-free code.

• Go emphasizes high-level concurrency with goroutines, offering simplicity but no


compile-time guarantees.

7.2.3 Type Systems and Expressiveness

Feature C23 Rust Go


Strong typing Yes Yes Yes
Generics / templates No Yes Yes
Bit-precise types Yes (_BitInt) Yes No
Decimal floating-point Yes (_Decimal32/64/128) No No

Insight:

• C23 introduces bit-precise integers and decimal floating-point, supporting numeric


and embedded applications.
137

• Rust and Go support generic programming, enabling reusable abstractions and


modern software architecture patterns.

7.2.4 Tooling and Ecosystem

Aspect C23 Rust Go


Compiler tooling Yes Yes (cargo + rustc) Yes (go build, go
fmt)
Package No Yes (crates.io) Yes (go modules)
management (manual)
Static analysis Yes Yes (clippy, rust-analyzer) Yes (golangci-lint)

Insight:

• C23 remains low-level and relies on external tooling.

• Rust and Go provide integrated build and analysis systems, improving


productivity and safety.

7.2.5 Philosophy and Use Cases


• C23:

– Focused on low-level control, minimal runtime overhead, and backward


compatibility.

– Ideal for embedded systems, operating systems, and high-performance


software.

• Rust:
138

– Memory- and concurrency-safe, expressive type system, and modern


abstractions.
– Ideal for safety-critical systems, secure applications, and modern system-level
projects.

• Go:

– Simple syntax, garbage-collected, with built-in concurrency.


– Ideal for network services, cloud infrastructure, and rapid development
projects.

7.2.6 Key Takeaways


• C23 modernizes C while preserving efficiency, portability, and system-level
control.

• Rust and Go offer higher-level safety and productivity features, but with trade-
offs in performance, memory control, or runtime behavior.

• System programmers should view C23 as a foundation for high-performance,


low-level systems, while adopting Rust or Go where memory safety, rapid
development, or concurrency guarantees are prioritized.
139

7.3 Why C Remains Relevant in Embedded and Systems


Programming
Despite the emergence of modern languages like Rust and Go, C continues to be the
primary choice for embedded systems and low-level programming. Its relevance stems
from a combination of performance, control, portability, and ecosystem maturity.

7.3.1 Direct Hardware Access


• C provides fine-grained control over memory, CPU registers, and I/O ports.

• Embedded systems, firmware, and operating system kernels rely on precise control
of hardware resources, which higher-level languages abstract away.

7.3.2 Minimal Runtime and Predictable Behavior


• C generates compact, efficient binaries with minimal runtime overhead.

• Deterministic execution and predictable memory usage are critical for real-time
systems and safety-critical applications.

7.3.3 Portability and Standardization


• C is standardized across microcontrollers, ARM, x86, RISC-V, and specialized
architectures.

• Modern C23 features maintain backward compatibility, ensuring that legacy


codebases can be safely migrated without losing hardware portability.
140

7.3.4 Rich Ecosystem and Proven Toolchains


• Decades of compilers, debuggers, static analyzers, and libraries support every
major platform.

• Embedded developers benefit from extensive community knowledge, mature


RTOS support, and vendor-provided SDKs.

7.3.5 Performance and Efficiency


• C allows manual memory management, low-level optimization, and precise bit-
level control.

• Many embedded applications, such as motor control, sensor processing, and


communication protocols, require high-performance code with minimal latency.

7.3.6 Modern Enhancements in C23


• Features like bit-precise integers (_BitInt), decimal floating-point types, UTF-8
support, and secure memory functions make C23 even more suitable for modern
embedded and system-level development.

• Developers can now write safer and more expressive code without sacrificing
deterministic performance.

7.3.7 Key Takeaways


• C remains the dominant language for low-level and embedded programming due
to its control, efficiency, and portability.

• C23 enhances C with modern features while preserving its core advantages,
ensuring C’s relevance for decades to come.
141

• Professionals in embedded systems, firmware, and operating system development


will continue to rely on C as the foundation of high-performance, low-level
software.
Appendices

Full Reference Tables


This section provides quick-access reference tables for all new C23 features, keywords,
attributes, macros, and deprecated or removed items. These tables are designed for
professional system programmers and embedded engineers who need to consult C23
updates efficiently.

New Keywords in C23

Keyword Description
alignas Specifies the alignment of a variable or type.
alignof Returns the alignment requirement of a type.
thread_local Declares thread-local storage.
nullptr Represents the null pointer constant.
true Boolean true value.
false Boolean false value.
static_assert Performs compile-time assertions.

142
143

New Attributes

Attribute Purpose
[[deprecated]] Marks functions, variables, or types as deprecated.
[[fallthrough]] Indicates intentional fall-through in switch statements.
[[nodiscard]] Warns if a function’s return value is discarded.
[[maybe_unused]] Suppresses warnings for unused variables or parameters.
[[noreturn]] Marks functions that do not return.
[[reproducible]] Indicates deterministic behavior.
[[unsequenced]] Specifies unsequenced evaluation of expressions.

New Feature-Test Macros

Macro Purpose
__STDC_IEC_60559_BFP__ Indicates support for IEEE-754
binary floating-point arithmetic.
__STDC_IEC_60559_DFP__ Indicates support for IEEE-754
decimal floating-point arithmetic.
__STDC_IEC_60559_COMPLEX__ Indicates support for IEEE-754
complex arithmetic.
__STDC_VERSION__ Reflects the current C standard
version (202311L for C23).
__STDC_VERSION_FENV_H__ Library version for <fenv.h>
support.
__STDC_VERSION_MATH_H__ Library version for <math.h>
support.
144

Macro Purpose
__STDC_VERSION_STDINT_H__ Library version for <stdint.h>
support.
__STDC_VERSION_STDLIB_H__ Library version for <stdlib.h>
support.
__STDC_VERSION_TGMATH_H__ Library version for <tgmath.h>
support.
__STDC_VERSION_TIME_H__ Library version for <time.h>
support.
__STDC_VERSION_STDCKDINT_H__ Library version for <stdckdint.h>
support.
__STDC_VERSION_STDBIT_H__ Library version for <stdbit.h>
support.

Removed or Deprecated Features

Item Status Notes


Old-style function Removed Use standard prototypes.
declarations
Non–two’s complement Removed C23 requires two’s complement
integers representation.
Mixed wide string literal Removed Standard string concatenation only.
concatenation
realloc(0) Undefined Avoid zero-size allocations.
behavior
145

Item Status Notes


<stdnoreturn.h> Deprecated Use [[noreturn]] or <assert.h>.
<stdalign.h> Deprecated Use alignas/alignof.
<stdbool.h> Deprecated true/false are keywords now.
_Noreturn specifier Deprecated Use [[noreturn]].
asctime(), ctime() Deprecated Use gmtime_r()/localtime_r() for thread
safety.
__STDC_IEC_559__ Deprecated Superseded by
__STDC_IEC_60559_BFP__.
DECIMAL_DIG Deprecated Use type-specific macros:
FLT_DECIMAL_DIG,
DBL_DECIMAL_DIG, etc.
INFINITY, NAN Deprecated Use <float.h> constants or functions.

Key Notes for Reference


• These tables are designed for quick look-up during coding or code review.

• They focus on new, removed, and updated elements in C23 to make migration
and adoption efficient and error-free.

• For in-depth explanations and examples, refer to the main chapters of this
booklet.
146

Sample Code Listings (Ready-to-Compile)

This section provides practical, ready-to-compile C23 code examples covering new
keywords, attributes, macros, and library features. These samples are designed for
system programmers, embedded engineers, and professional C developers to quickly
experiment with C23 features.

Using New Keywords

#include <stdio.h>
#include <stdalign.h>
#include <threads.h>

alignas(16) int aligned_array[4]; // Aligned array


thread_local int tls_counter = 0; // Thread-local variable

int main(void) {
int *p = nullptr; // Null pointer
if (p == nullptr) {
printf(”Pointer is null\n”);
}

static_assert(sizeof(int) == 4); // Compile-time assertion


printf(”Size of int: %zu\n”, sizeof(int));
return 0;
}
147

Using New Attributes

#include <stdio.h>

[[nodiscard]] int compute_value() {


return 42;
}

int main(void) {
[[maybe_unused]] int x = compute_value(); // Compiler warns if ignored
[[deprecated]] void old_function();

old_function(); // Warning: function is deprecated


return 0;
}

[[deprecated]]
void old_function() {
printf(”Deprecated function called\n”);
}

Bit-Precise Integers and Decimal Floating-Point

#include <stdio.h>
#include <stdbit.h>

_BitInt(5) a = 17; // 5-bit integer


_Decimal64 pi = 3.1415926535DL;

int main(void) {
148

printf(”BitInt value: %d\n”, a);


printf(”Decimal64 value: %Lf\n”, pi);
return 0;
}

Binary Integer Constants and Digit Separators

#include <stdio.h>

int main(void) {
int binary = 0b1010'1101; // Binary literal with digit separator
printf(”Binary value: %d\n”, binary);
return 0;
}

UTF-8 Support

#include <uchar.h>
#include <stdio.h>

int main(void) {
char8_t utf8_char = u8'A';
printf(”UTF-8 char: %c\n”, utf8_char);
return 0;
}
149

Safe Memory Handling

#include <string.h>
#include <stdio.h>

int main(void) {
char secret[16] = ”topsecret”;
memset_explicit(secret, 0, sizeof(secret)); // Clear sensitive data
return 0;
}

New Preprocessor Directives

#if defined(__STDC_VERSION__)
#warning ”Compiling with C23 features”
#endif

#elifdef FEATURE_X
#embed ”data.bin”
#endif

Thread-Local Storage Example

#include <threads.h>
#include <stdio.h>

thread_local int counter = 0;


150

int main(void) {
counter++;
printf(”Thread-local counter: %d\n”, counter);
return 0;
}

Key Notes
• All code is ready to compile with C23-compliant compilers.

• Examples cover keywords, attributes, numeric types, UTF-8, memory safety, and
preprocessor features.

• Developers can copy and modify these snippets to experiment, test, and adopt
C23 features in real projects.
151

References to WG14 Documents


This section provides authoritative references to the ISO/IEC C Working Group 14
(WG14) documents, which track the evolution of the C standard and provide the
official source material for C23 and its drafts.

Official C Standards

Standard ISO/IEC Reference Notes


C89 / C90 ISO/IEC 9899:1990 First standardized C version.
C99 ISO/IEC 9899:1999 Introduced inline, variable-length arrays, and new
data types.
C11 ISO/IEC 9899:2011 Added atomic types, threads, Unicode support.
C17 ISO/IEC 9899:2018 Mainly bug fixes and clarifications over C11.
C23 ISO/IEC 9899:2024 Latest revision, new keywords, attributes, macros,
and library features.

Public Drafts for Reference

Draft WG14 Document Date Notes / Access


Number
C23 Working n3149 2023-07-09 Password-protected official
Draft (WD) draft.
C2Y Draft n3220 2024-02-22 Publicly accessible, nearly
identical to final C23 except
editorial changes.
152

Draft WG14 Document Date Notes / Access


Number
C23 Draft n3221 2024-02-22 Summary of changes from
Summary n3220 to final draft.

WG14 Online Resources

Resource URL Description


WG14 https://www.open-std.org/jtc1/ Official working group for C
Homepage sc22/wg14/ standard development.
Draft https://www.open-std.org/jtc1/ Archive of working drafts,
Documents sc22/wg14/www/docs/ technical corrigenda, and
meeting notes.
C23 Drafts https://www.open-std.org/jtc1/ First publicly accessible draft
sc22/wg14/www/docs/n3220.pdf close to C23 final.

Recommended Usage
• Use these WG14 references to verify language changes, check draft revisions, or
cross-reference features in C23.

• Professional developers and systems engineers can consult these documents to


ensure standards compliance and correct usage of new C23 features.
References

ISO/IEC C Standards and WG14 Documents


• ISO/IEC 9899:2024 (C23) – Final C23 standard.

• WG14 Working Draft n3149 (2023-07-09) – Official password-protected draft.

• C2Y Draft n3220 (2024-02-22) – Public draft nearly identical to C23 final.

• WG14 Document Archive – https://www.open-std.org/jtc1/sc22/wg14/www/


docs/

Official WG14 Pages and Technical Reports


• WG14 Home: https://www.open-std.org/jtc1/sc22/wg14/

• Drafts, Technical Corrigenda, and Change Logs for all C standards.

Compiler Documentation (C23 Support)


• GCC 15.x Documentation – C23 support notes, library updates, keywords, and
extensions.

153
154

• Clang 16.x Documentation – C23 compliance, feature macros, and new attributes.

• Microsoft Visual Studio 2022/2023 – C23 features supported and upcoming


compiler improvements.

Reference Books and Articles


• “The C Programming Language” – Brian W. Kernighan & Dennis M. Ritchie.

• ISO/IEC C Committee Technical Reports – WG14 minutes and proposals.

• Articles on modern C standards, C23 feature updates, and embedded/system


programming applications.

Online Resources and Libraries


• Compiler test suites and reference implementations for C23 features.

• Online forums and professional C communities for feature discussions and best
practices.

Key Notes for Readers


• These references were used to compile factual, accurate, and modern coverage of
C23 in this booklet.

• Developers are encouraged to consult official WG14 documents for full


specifications and formal clarifications.

• This booklet condenses, summarizes, and exemplifies C23 features for practical
professional use, but the official documents remain the ultimate authority.

You might also like