The C23 Deprecated and Removed Collection

As with all language updates, things change. Some of these items are deprecated while others are outright removed. Here’s the list.

According to the cppreference.com website, the following items are removed from the C language with the C23 standard:

• Old-style function declarations and definitions you’ve probably never used, but which are defined in the original K&R. For example:

int swap(a,b)
    int *a, b;
{
    /* stuff */
}

I don’t know anyone who declares a function with the variable list presented as above. The current form was introduced with C89.

• Representations for signed integers other than two’s complement.

Without getting too geeky, signed integer values typically range from -2n-1 to +2n-1-1. For example, -128 through 127 for a signed char data type. Some obscure compilers set these values as -127 through 127, which isn’t supported in the C23 standard.

• Permission that u/U-prefixed character constants and string literals may be not UTF-16/32
• Mixed wide string literal concatenation

Both of these items can be confusing, but they’re cleaning up definitions for wide and multibyte characters. The C23 standard brings consistency to expressing wide character and multibyte literals by removing the old definitions for the u and U character prefixes that were inconsistent or ill-defined.

• Support for calling realloc() with zero size

The realloc() function can reallocate a memory chunk to zero bytes. When you do so, different things can happen depending on the compiler, e.g., is the memory block freed? In the C23 standard, the behavior of reallocating memory to zero bytes is officially flagged as “undefined.”

__alignof_is_defined and __alignas_is_defined

These macros are removed in C23. If used, they return constant 1 (TRUE).

static_assert is not provided as a macro defined in
thread_local is not provided as a macro defined in

The old static_assert macro is now the new keyboard _Static_assert; thread_local becomes keyword _Thread_local.

The list of Deprecated items is rather long but contains a few things you may recognize. Before showing the list, remember that deprecated doesn’t mean that the function or feature is no longer available. It means that you should avoid using the functions in future code as a better, stronger way to do the task is available.

Two functions being deprecated as asctime() and ctime().

The asctime() function converts a time/date value stored in a tm structure into a string. The string isn’t the issue, but rather that values in the tm structure can be out of range. The function’s behavior for dealing with out of range values is undefined, which is probably why this function is being deprecated. The asctime_s() function can be used as a substitute.

The ctime() function converts a clock tick (time_t) value into a string. If I’m reading the docs correctly, this function works by calling the asctime() function internally, which would explain why it’s also being deprecated. The substitute function is ctime_s().

The deprecated list also includes the stdnoreturn.h header file plus a few macros I’m unfamiliar with. The math.h defined constants/macros INFINITY, DEC_INFINITY, NAN, and DEC_NAN are now found in the float.h header file.

You can view more details at the cppreference.com website. The site also features a table that shows current compilers and their C23 status.

5 thoughts on “The C23 Deprecated and Removed Collection

  1. »Old-style function declarations and definitions you’ve probably never used«
    Sorry for being a smart Alec, but unfortunately those were used all too often:

    int main() { … } /* K&R function declaration for a variadic function, i.e. a function that can be called with a variable number of arguments (of nearly arbitrary type) */

    Up until now one had to write int main(void) { … } to define a programʼs entry point as a function taking no arguments. With K&R functions out of the windows, however, omitting void in (void) can finally be defined to mean the same thing as in C++, namely the declaration of a function taking no arguments.

    »Representations for signed integers other than two’s complement.«
    I had to look this up myself, but—fun fact—there still seem to be systems out there that use onesʼ complement . Sidenote: sometimes I wonder, if onesʼ complement wouldnʼt have been the better solution after all:
    signed char sc = -128;
    sc *= -1;  /* Oopsie, still the same (-128) value */

    … having -0 as a potential flag value surely would have its uses as well

    »Permission that u/U-prefixed character constants and string literals may be not UTF-16/32«
    While all compilers I know defaulted to these encodings anyway, up until now one couldnʼt be sure u"doppelgänger" would get encoded in UTF-16. Likewise, there was no guarantee that a compiler in question would encode U"doppelgänger" in UTF-32. If the new standard finally mandates both encodings then thatʼs certainly A Good Thing™ ☺

  2. I assume ctime calls localtime to get a tm from a time_t, and uses the various bits of the date and time in a string. I therefore don’t understand the problem as any negative or positive time_t value is a valid date before or after midnight on 1 Jan 1970 and so localtime will create valid tm values.

    The problem with a tm is when it has been populated in code rather than from a time_t, as you set set any old rubbish such as 32 January. Calling mktime will correct any errors, for example changing 32 January to 1 February. Does asctime_s do this before creating a string? Has strftime been dumped as well? It’s basically the same as asctime but with customisable formats.

    IMHO best practice is to always use a time_t variable, just using a tm for input/output and maybe calculations. For example if you need to add a number of days just go ahead and add them, and then let mktime sort out stuff like 99 August.

    I believe two’s complement now dominates because it’s easier to carry out addition – you just add numbers as they are, -ve or +ve, whereas one’s complement needs an interim step. Something like that anyway.

  3. I’m still researching a lot of this, so if I find definitive answers or examples, I’ll be sure to pass them along.

  4. @ChrisWebb
    Sorry for this late reply—had (and still am having) a busy week.

    »because it’s easier to carry out addition – you just add numbers as they are, -ve or +ve, whereas one’s complement needs an interim step.«
    Didnʼt have to much time to really look into this, but what youʼre probably referring to is the concept of “end-around carry” (as described under the Signed_number_representations article on Wikipedia). Interesting, didnʼt know that.

    Through Ones-complement arithmetic: it lives! I also stumbled over the following Google Groups discussion,
    C is impractical on oneʼs-complement machines, but didnʼt really have time to look into any of the brought up arguments (yet).

    That being said, it is my impression that most of the difficulties raised with regards to onesʼ complement seem to revolve around the necessity of making sure to not generate any -0ʼs (instead of +0ʼs).

    Even though I havenʼt looked into this any further, I donʼt find these arguments too convincing. Thatʼs because to me it seems like most of the pain of avoiding -0 (people seem to talk about when onesʼ complement comes up) should go away if the hardware were to guarantee that no (arithmetic) operation ever resulted in one (as at least some of the onesʼ complement machines that existed/still exist today seem to guarantee).

    I can see that hardware implementations might be a bit harder to do, but with todayʼs billion transistors on a chip I don’t think this argument is on too firm ground either.

    Of course, all of this is is purely an academic exercise anyway. Twoʼs complement “won” and thatʼs that I guess.

Leave a Reply