https://lemire.me/blog/2024/01/21/c23-a-slightly-better-c/ Skip to content Daniel Lemire's blog Daniel Lemire is a computer science professor at the Data Science Laboratory of the Universite du Quebec (TELUQ) in Montreal. His research is focused on software performance and data engineering. He is a techno-optimist and a free-speech advocate. Menu and widgets * My home page * My papers * My software Join over 12,500 email subscribers: [ ][Go!] You can follow this blog on telegram. You can find me on twitter as @lemire or on Mastodon. Search for: [ ] [Search] Support my work! I do not accept any advertisement. However, you can you can sponsor my open-source work on GitHub. Recent Posts * C23: a slightly better C * How much memory bandwidth do large Amazon instances offer? * Estimating your memory bandwidth * Implementing the missing sign instruction in AVX-512 * Science and Technology links (December 30th 2023) Recent Comments * Oren Tirosh on C23: a slightly better C * Antoine on C23: a slightly better C * Bill Broadley on How much memory bandwidth do large Amazon instances offer? * Daniel Lemire on How fast can you validate UTF-8 strings in JavaScript? * WilliamF on How fast can you validate UTF-8 strings in JavaScript? Pages * A short history of technology * About me * Book recommendations * Cognitive biases * Interviews and talks * My bets * My favorite articles * My favorite quotes * My rules * Newsletter * Predictions * Privacy Policy * Recommended video games * Terms of use * Write good papers Archives Archives [Select Month ] Boring stuff * Log in * Entries feed * Comments feed * WordPress.org C23: a slightly better C One of the established and most popular programming languages is the C programming language. It is relatively easy to learn, and highly practical. Maybe surprisingly, the C programming language keeps evolving, slowly and carefully. If you have GCC 23 or LLVM (Clang) 16, you already have a compiler with some of the features from the latest standard (C23). // Only include stdio.h if it exists #if __has_include () #include #endif #include [[deprecated]] void f() {} [[nodiscard]] int g(int x) { return x + 1; } int main() { f(); // compile-time warning: 'f' is deprecated g(1); // compile-time warning auto x = 0b1111; typeof(x) y = 1'000'000; // type of y is the same as x printf("%d\n", x); // prints 15 printf("%d\n", y); // prints 1000000 constexpr int N = 10; // compile-time asserts using static_assert static_assert (N == 10, "N must be 10"); bool a[N]; // array of N booleans for (int i = 0; i < N; ++i) { a[i] = true; } printf("%d\n", a[0]); // prints 1 } 1. The first part of the code contains some preprocessor directives, which are instructions for the compiler to process the source code before compiling it. The #if directive checks a condition at compile time and includes the following code only if the condition is true. The __has_include macro is a feature of C++17 adopted by C23 that checks if a header file exists and can be included. In this instance, it is not useful because we know that stdio.h is present, but in other instances, this can prove useful to determine what headers are available. 2. The next part of the code defines two functions with attributes, which are annotations that provide additional information to the compiler about the behavior or usage of a function, variable, type, etc. + The [[deprecated]] attribute is a feature of C++14 adopted by C23 that marks a function as obsolete and discourages its use. The compiler will issue a warning if the function is called or referenced. + The [[nodiscard]] attribute is a feature of C++17 adopted by C23 that indicates that the return value of a function should not be ignored or discarded. The compiler will issue a warning if the function is called from a discarded-value expression. In this case, the function f is deprecated and does nothing, while the function g returns the input value plus one and should not be ignored. The first two lines of the main function call the functions f and g and trigger the warnings. 3. The third line of the main function declares a variable x with the auto keyword, which is a feature of C++11 that lets the compiler deduce the type of the variable from its initializer. In this case, the initializer is a binary literal, which is a feature of C++14 and adopted by C23 that allows writing integer constants in binary notation using the prefix 0b. The value of x is 0b1111, which is equivalent to 15 in decimal. 4. The fourth line declares another variable y with the typeof operator that returns the type of an expression. In this case, the expression is x, so the type of y is the same as the type of x. The initializer of y is a digit separator, which is a feature of C++14 adopted by C23 that allows inserting single quotes between digits in numeric literals to improve readability. The value of y is 1'000'000, which is equivalent to 1000000 in decimal. 5. The seventh line declares a constant variable N with the constexpr keyword, which is a feature of C++11 adopted by C23 that indicates that the value of the variable can be evaluated at compile time. The value of N is 10. Previously, one would often use a macro to define a compile-time constant (e.g., #define N 10). 6. The eighth line uses the static_assert keyword, which is a feature of C++11 adopted by C23 that performs a compile-time assertion check. The keyword takes a boolean expression and an optional string message as arguments. If the expression is false, the compiler will emit an error and stop the compilation, displaying the message. If the expression is true, the compiler will do nothing. In this case, the expression is N == 10, which is true, so the compilation continues. 7. The ninth line declares an array of N booleans named a. An array is a collection of elements of the same type that are stored in contiguous memory locations. The size of the array must be a constant expression, which is why N is declared with constexpr. We also use the keywords true and false which become standard in C23. There are many more features in C23, but it will take some time for compilers and system librairies to catch up. My thoughts so far: * The introduction of consexpr in C will probably help reduce the dependency on macros, which is a good idea generally. Macros work well in C, but when a bug is introduced, it can be difficult get meaningful error messages. It does not happen too often, but in large code bases, it can be a problem. * I personally rarely use auto and typeof in other languages, so I don't expect to use them very much in C. In some specific cases, it can greatly simply one's code, however. It is likely going to help reduce the reliance on macros. * The idea behind static_assert is great. You run a check that has no impact on the performance of the software, and may even help it. It is cheap and it can catch nasty bugs. It is not new to C, but adopting the C++ syntax is a good idea. * The __has_include feature can simplify supporting diverse compilers. It is good idea. Published by [2ca999] Daniel Lemire A computer science professor at the University of Quebec (TELUQ). View all posts by Daniel Lemire Posted on January 21, 2024January 21, 2024Author Daniel Lemire Categories 2 thoughts on "C23: a slightly better C" 1. [ad4ee7] Antoine says: January 21, 2024 at 8:07 pm The introduction of consexpr in C will probably help reduce the dependency on macros, which is a good idea generally. Defining constants is probably the most harmless and easiest to debug usage of macros in C, so I wouldn't be that optimistic. That said, pleasant surprises from C. It seems they finally picked up a bunch of easy quality-of-life improvements from C++. Reply 2. [5e02c0] Oren Tirosh says: January 21, 2024 at 8:41 pm Any features without a c++ heritage? Reply Leave a Reply Cancel reply Your email address will not be published. To create code blocks or other preformatted text, indent by four spaces: This will be displayed in a monospaced font. The first four spaces will be stripped off, but all other whitespace will be preserved. Markdown is turned off in code blocks: [This is not a link](http://example.com) To create not a block, but an inline code span, use backticks: Here is some inline `code`. For more help see http://daringfireball.net/projects/markdown/syntax [ ] [ ] [ ] [ ] [ ] [ ] [ ] Comment * [ ] Name * [ ] Email * [ ] Website [ ] [ ] Save my name, email, and website in this browser for the next time I comment. Receive Email Notifications? [no, do not subscribe ] [instantly ] Or, you can subscribe without commenting. [Post Comment] [ ] [ ] [ ] [ ] [ ] [ ] [ ] D[ ] You may subscribe to this blog by email. Post navigation Previous Previous post: How much memory bandwidth do large Amazon instances offer? Terms of use Proudly powered by WordPress