gcc-15 switched to C23

November 17, 2024

Tl;DR

In November gcc merged the switch from C17 (-std=gnu17) to C23 (-std=c23) language standard used by default for C code.

This will cause quite a few build breakages in projects written in C. A few example fixes:

more words

C23 has a few high-visibility breaking changes compared to C17.

bool, true, and false are unconditionally predefined

true and false are now predefined constants (instead of being a part of <stdbool.h> macros and typedefs). Thus code like below does not compile any more:

enum { false = 0; }
typedef int bool;

Error messages:

$ printf 'enum { false = 0 };' | gcc -std=c17 -c -x c -
$ printf 'enum { false = 0 };' | gcc -c -x c -
<stdin>:1:8: error: expected identifier before 'false'

$ printf 'typedef int bool;' | gcc -std=c17 -c -x c -
$ printf 'typedef int bool;' | gcc -c -x c -
<stdin>:1:13: error: two or more data types in declaration specifiers
<stdin>:1:1: warning: useless type name in empty declaration

The fix is usually to use <stdbool.h> or avoid name collisions.

Example affected project is linux.

partially defined int (*)() function prototypes are just int (*)(void) now

This one is trickier to fix when intentionally used. C happened to allow the following code:

// $ cat a.c
typedef void (*PF)();

static int f0(void)  { return 42; }
static int f1(int a) { return 42 + a; }

int main() {
    PF pf;

    // 0-argument function pointer
    pf = f0;
    pf();

    // 1-argument function pointer
    pf = f1;
    pf(42);

    // 3-argument function pointer: an odd one, but happens to work
    pf(42,42,42);
}

But not any more:

$ gcc -std=c17 -c a.c
$ gcc -c a.c
a.c: In function 'main':
a.c:15:8: error: assignment to 'PF' {aka 'int (*)(void)'} from incompatible pointer type 'int (*)(int)' [-Wincompatible-pointer-types]
   15 |     pf = f1;
      |        ^
a.c:16:5: error: too many arguments to function 'pf'
   16 |     pf(42);
      |     ^~
a.c:19:5: error: too many arguments to function 'pf'
   19 |     pf(42,42,42);
      |     ^~

This hack is used at least in ski, ghc and ncompress. But more frequently it’s use is an accident (ell, iwd, bash and a few others).

parting words

Quick quiz: the above changes look like they tickle some very obscure case. How many packages are affected on a typical desktop system? What would be your guess? 1? 5? 100? 1000?

So far on my system (~2000 installed packages) I observed the failures of the following projects:

That’s more than 80 packages, or about 4% of all the packages I have.

Looks like gcc-15 will be a disruptive release (just like gcc-14) that will require quite a few projects to adapt to new requirements (either by fixing code or by slapping -std=gnu17 as a requirement).

Most of the breakages above are not yet fixed upstream. These can be good first contribution fixes if you are thinking of making one.

Have fun!