DEV Community

Paul J. Lucas
Paul J. Lucas

Posted on

C23 Miscellany

#c

Introduction

I’ve written a few articles on individual new features in C23 covering attributes, auto, bool, storage classes for compound literals, constexpr, explicit underlying types for enumerations, nullptr, and typeof. 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 at a minimum, you had to include a 0 between the { and }.

Binary Literals

C has had decimal, octal, and hexadecimal integer literals since its creation. C23 adopted binary literals from C++14 using either the same 0b or 0B prefix:

int n = 0b101010;  // 42 decimal
Enter fullscreen mode Exit fullscreen mode

_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
Enter fullscreen mode Exit fullscreen mode

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 of _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 same rounding errors that the standard-floating types are. The standard-floating types are still better for general floating-point calculations.

Declarations After Labels

You can now (finally) put declarations immediately after either goto or case labels:

error:             // C < C23: error; C23: OK
  int code;
Enter fullscreen mode Exit fullscreen mode

Previously, you had to use something like the :; trick (an empty statement after :) 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 digits separator from C++14 as a readability aid:

int n = 0b0010'1010;
int c = 299'792'458;
Enter fullscreen mode Exit fullscreen mode

The overall value is not affected. You’re free to group the digits however you like.

If you’re wondering why , (comma) wasn’t used, it’s because , is used to separate function arguments and is also the comma operator.

K&R-Style Functions

Even though function prototypes were adopted from C++ way 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;
{
  // ...
Enter fullscreen mode Exit fullscreen mode

Finally, 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

Unlike C++, function definitions in C have historically required unused parameters to still be named. To eliminate an “unused” warning, you typically cast it to void:

char** cdecl_rl_completion( char const *text,
                            int start, int end ) {
  (void)end;  // means: unused
  // ...
Enter fullscreen mode Exit fullscreen mode

In C23, you can simply omit the name just like you always could in function declarations.

__VA_OPT__

Though it’s been supported as an extension by gcc and clang for a while, __VA_OPT__ is finally part of the C standard.

Variadic Functions

As I mentioned in a previous article, variadic functions no longer insist on at least one required parameter; that is you can do:

void f( ... ) {      // C23: no required parameter
  va_list args;
  va_start( args );  // C23: no second argument
  // ...
Enter fullscreen mode Exit fullscreen mode

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).

Top comments (0)