The year is 2023 and you’re asking “What’s new in C?” Surely the answer is “absolutely nothing”, right?
Wrong!
C23 will be released in the coming months (likely in early 2024), and this is a whirlwind tour of what changes were made for the latest revision of one of the world’s most popular programming languages.
I originally prepared this talk for NDC Tech Town in Kongsberg, but I was unable to give the talk because a hurricane + poor airline services interrupted my travel plans. Oh well, their loss is your gain! I hope you enjoy the talk.
Errata
- The slide about underlying enumeration types did not make it clear that the choice of the underlying type for the enumeration type is implementation-defined, so the given types in the comments might be incorrect depending on your implementation.
- When mentioning that signed overflow is still implementation-defined, I misspoke. I was talking about this situation involving unsigned -> signed conversion:
unsigned int i = UINT_MAX;
signed int j = i; // Implementation-defined behavior
However, signed *overflow* is still undefined behavior, as it always was. e.g.,
signed int i = INT_MAX + 1; // Undefined behavior
Can we just go back to C99?
Sad that defer won’t be in C23
Cool video, but I wish it was on YouTube!
The slide at the 24:22 minute mark indicates that a string literal will be deduced to non-const pointer. I am far better versed in C++ than C, but is that not likely to cause problems? Or is a string literal in C generally not considered constant and this is nothing new?
That’s been a long-standing oddity of C for…ever-ish. It causes type confusion, but isn’t too much of a problem in practice because attempting to *modify* a string literal is undefined behavior, and so most folks are used to treating string literals as though they were const-correct.
Here’s an example showing the type difference between C and C++: https://godbolt.org/z/YexxnsWeo
(1) That would explain it for sure – wild, but if you’re used to it you’re used to it.
(2) Thank you for that very speedy answer (I also ran to Godbolt immediately, but that was to throw is_same_v at the problem, suddenly thinking that maybe I’d been wrong about C++ string literals all these years)
I loved this! A lot of stuff in here will be relevant to my day-to-day use. I have my own messy version of #embed that would be great to replace with something more compact.
Thanks for the work you do and the detailed breakdown!
If #embed is, as described, a pre-processor directive (as its syntax suggests), then (a) why is the text form of the list of integers that it produces not described in the draft and (b) how does that help, compared to #including the equivalent set of integers?
Don’t you have to have something operating at the compiler/AST level to get the supposed performance benefit?
The phrasing there is more of an “as-if” than “this is how the standard describes the feature”, so it is imprecise. The reason you get benefit from #embed over #include in terms of performance is because #include is for textual inclusion that the rest of the compiler then has to lex + parse, whereas with #embed, you can park an intrinisic function that says “when you need the data for that, you can find it over here” and not do the lexing and parsing unless needed, and you can use tricks like mmap to access the data more quickly than opening it as a text stream.
I would not recommend trying to implement the feature as though it was dumping a comma-delimited list of elements into source, that would almost certainly be slow.
It’s always been possible to have named compile-time integer constants whose name is not removed by the C preprocessor.
static constexpr int Size = 12;
does not seem like an improvement in expressiveness or clarity when compared to
enum { Size = 12 };
The improvement in expressivity and clarity is that constexpr allows you to specify the underlying type of the variable. With enumeration constants, you get whatever underlying type you get from the compiler, which isn’t always what you want (or even portably possible prior to C23 if you needed something like a ‘long long’ constant).