void foo()
now means void foo(void)
In C17 and earlier, void foo()
means “I haven't yet told you how many arguments this function has”. In C23, it's equivalent to C++ and means “this function has no arguments”. This may surface as a function pointer type mismatch, because previously ()
matched functions taking any arguments, whereas in C23 it only matches functions taking no arguments.
Fix: in cases where your function does have arguments, declare them.
In C17 and earlier, calling foo(123)
without a declaration for foo()
produced a warning. In C23 this is an error instead. One common special case of this is code that's explicitly ignoring such warnings to call functions that are GNU extensions; such code should be fixed to ensure that _GNU_SOURCE
is defined before any header is included instead (often by adding -D_GNU_SOURCE
to the cflags in the build file).
Fix: add the missing forward declaration or #include
(or -D_GNU_SOURCE
).
bool
/true
/false
are now keywordsIn C17 and earlier, only code that included <stdbool.h>
would have standard definitions for these (typically macros for _Bool
/1
/0
). In C23 these are keywords and should no longer be defined in your code.
Fix: delete any definitions of bool
/true
/false
if you only need to build as C23, or switch to #include <stdbool.h>
for compatibility back to C99.
false
is no longer 0
In C17 and earlier, it was common for true and false to be defined as 1 and 0 (either by <stdbool.h>
or by user-provided #define
/enum
). This meant that false
(as 0) could be implicitly converted to NULL
. In C23, a function that returns (or takes) a pointer can no longer return false
(or be passed false
).
Fix: return/pass NULL
(or nullptr
for C23-only code) instead of false
in pointer contexts.
unreachable()
is now a predefined function-like macro in <stddef.h>
In C17 and earlier, unreachable()
was available for your own macros/functions. In C23 there's a standard definition.
Fix: delete your unreachable()
if it was just equivalent to __builtin_unreachable()
or rename it if it had different behavior.
In C17 and earlier, K&R function prototypes were deprecated but still allowed. In C23 K&R prototypes are no longer allowed.
Fix: rewrite any K&R prototypes as ANSI/ISO prototypes.
In C17 and earlier you'd have to use __attribute__((unused))
on an unused function parameter. In C23 you can just omit the parameter name instead, like void* pthread_callback_fn(void*) {
(as in C++).
C23 adds [[deprecated("reason")]]
, [[fallthrough]]
, [[nodiscard]]
(the equivalent of the clang attribute warn_unused_result
), [[maybe_unused]]
(the equivalent of the clang attribute unused
), and [[noreturn]]
(equivalent to C11 _Noreturn
). Most of these have been available before via __attribute__
or other syntax, but are now standard.
#embed
You can now include binary data directly into an array or string: https://en.cppreference.com/w/c/preprocessor/embed
void foo(...)
is now allowedIn C17 and earlier, a varargs function needed a non-varargs argument. In C23 this is allowed (as in C++).
enum
base typesYou can now say enum E : long { ... }
to explicitly choose the base type of your enum (as in C++, and already supported by clang as an extension).
nullptr
constantThere is now a nullptr
constant (as in C++), and a corresponding nullptr_t
type for that constant.
constexpr
There is now a limited form of constexpr
for defining const
variables (similar to, but much more limited than C++ constexpr).
Library changes are not covered here because bionic does not make library functionality available based on target C version, since the target API level distinctions are confusing enough already.
See status.md for what functionality went into which API level.