C99 initializers have been encouraged for a while.
_Static_assert is to be preferred to CTASSERT.
Just my opinion: _Static_assert() is longer, uglier, and the mandatory second argument is often not useful (since it's just a string, and not e.g. a printf format). It feels weird to have regular code directly invoking reserved identifiers (underscore capital), like directly using _Bool. I'd suggest we consider just leaving CTASSERT() alone and maybe adding a new CTASSERT1() wrapper.
I'd second this: _Static_assert() looks weird as it feels like reserved macro. Additionally, having a macro able to provide an error explanation directly without encoding it in the comments is pretty useful. I'd prefer either sticking with static_assert() or introducing CTASSERT1() wrapper.
From here: https://en.cppreference.com/w/c/error/static_assert it seems that the intention is that _Static_assert should be used publicly as static_assert() from <assert.h>. (Our assert.h defines it). This is indeed similar to _Bool vs bool where a header is used in userland (<stdbool.h>) to give the C++ name in C. What we have one for 'bool' in the kernel is to go ahead and define 'bool' in <sys/types.h> under #ifdef _KERNEL. I think something similar is probably ok in in <sys/systm.h> where we define 'static_assert' to '_Static_assert' and fix existing kernel code to use the C++ spelling.