C23 Miscellany
Source: Dev.to
Introduction
I’ve written a few articles on individual new features in C23 covering attributes, auto(link), bool(link), storage classes for compound literals, constexpr(link), explicit underlying types for enumerations, nullptr(link), and typeof(link). There are a few miscellaneous new features that aren’t substantial enough to warrant individual articles for each, so this article will cover them together.
Aggregate Initialization
You can now initialize aggregates (arrays, structures, and unions) with an empty = { }. Previously you had to include at least a 0 between the braces.
Binary Literals
C has had decimal, octal, and hexadecimal integer literals since its creation. C23 adopted binary literals from C++14 using either the 0b or 0B prefix:
int n = 0b101010; // 42 decimal
_BitInt
A new bit‑precise integer type has been added, _BitInt(n) where n is a positive constant integer expression. It may be either signed (the default) or unsigned. (If signed, n includes the sign bit.) Some examples:
unsigned _BitInt(24) rgb24; // 24‑bit RGB color
unsigned _BitInt(256) sha256; // SHA‑256
The maximum value for n is implementation‑defined, but is at least as many as for unsigned long long.
Decimal Floating‑Point Types
Although they’ve existed as extensions for a while, the new decimal floating‑point types _Decimal32, _Decimal64, and _Decimal128 are now officially supported.
Decimal‑floating types are better for calculations involving money (dollars, euros, pounds, etc.) because they’re not subject to the rounding errors that affect the standard floating‑point types. The standard floating‑point types remain preferable for general floating‑point calculations.
Declarations After Labels
You can now place declarations immediately after goto or case labels:
error: // C < C23: error; C23: OK
int code;
Previously you had to use a trick such as an empty statement after the colon (:;) to be legal. The C Committee should have made this legal when they allowed intermingled declarations and code in C99, but better late than never.
Digit Separators
C23 also adopted the ' character as a digit separator from C++14 as a readability aid:
int n = 0b0010'1010;
int c = 299'792'458;
The overall value is unchanged; you can group the digits however you like. A comma cannot be used because it already separates function arguments and serves as the comma operator.
K&R‑Style Functions
Even though function prototypes were adopted from C++ back in C89 (the first ANSI C), C has still supported “K&R style” function declarations and definitions:
char* strncpy(); // C < C23: unspecified arguments
char* strncpy( dst, src, n )
char *dst;
char const *src;
size_t n;
{
/* ... */
}
C23 has dropped support for such declarations and definitions.
New Keyword Spellings
In addition to bool replacing _Bool, alignas replaces _Alignas, alignof replaces _Alignof, static_assert replaces _Static_assert, and thread_local replaces _Thread_local. The old spellings are still supported but deprecated.
New Preprocessor Directives
The preprocessor now includes #elifdef, #elifndef, #embed, and #warning directives.
Unnamed, Unused Parameters
Historically, C required unused parameters to be named, and the common way to silence the “unused” warning was to cast the parameter to void:
char** cdecl_rl_completion( char const *text,
int start, int end ) {
(void)end; // unused
/* ... */
}
In C23 you can simply omit the name, just as you could in function declarations.
__VA_OPT__
Although it has been supported as an extension by GCC and Clang for a while, __VA_OPT__ is now part of the C standard.
Variadic Functions
As mentioned in a previous article, variadic functions no longer require at least one mandatory parameter; you can write:
void f( ... ) { // C23: no required parameter
va_list args;
va_start( args ); // C23: no second argument
/* ... */
}
This ability was adopted from C++.
Conclusion
Of all the changes to C23, auto will probably be the most used; but the other changes, while not revolutionary, are nice (and sometimes long overdue).