2023年11月現在の最新のCの国際規格ISO/IEC 9899:2018（通称C17）は、ISO/IEC 9899:2011(通称C11)の不明確な部分を補うErrata的な規格で、実質的にC11が現行の最新規格という状態が10年以上続いています。
 は、ISO/IEC 9899:2023（通称C2xまたはC23）を2023年11月を目標に策定しています[https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2984.pdf N2984], [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3132.pdf N3132], ([https://www.open-std.org/jtc1/sc22/wg14/www/wg14_document_log WG 14 Document Log])N3054によると、__STDC_VERSION__ は 202311L となるようです。。
ここでは、現在入手可能な working draft — September 3, 2022 ISO/IEC 9899:2023 (E)[https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3054.pdf N3054],[https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf N3096][https://www.reddit.com/r/C_Programming/comments/w5hl80/c23_now_finalized/ C23 now finalized!]に基づいて、C23のC11に対する変更点をまとめます。
第5版（2023年）のC言語標準（ISO/IEC 9899:2023）の変更点について、詳細に解説します。
新しいキーワードの追加: bool, static_assert, true, false, thread_localなどの新しいキーワードが追加されました。これにより、古いスペル（大文字で始まるアンダースコアに続く）のマクロを提供し、プログラムの移行を容易にすることが許可されました。
整数幅の制約の削除: 整数幅の制約や古い符号表現（「1の補数」と「符号-絶対値」）が削除されました。
static_assertの単一引数版の追加: static_assertの引数が1つだけのバージョンが追加されました。
識別子リストを持つ関数定義のサポートの削除: 識別子リストを持つ関数定義のサポートが削除されました。
空のパラメータリストを持つ関数宣言の扱いの変更: パラメータリストが空の関数宣言は、単一のvoidを含むパラメータリストと同じように扱われるようになりました。
POSIXとの調整: POSIXとの調整が行われ、strftimeのための拡張月名形式や、いくつかの関数（gmtime_r, localtime_r, memccpy, strdup, strndup）の統合が行われました。
IEC 60559浮動小数点規格との調和: IEC 60559浮動小数点規格との調和が行われ、バイナリ浮動小数点技術仕様TS 18661-1、10進浮動小数点技術仕様TS 18661-2、および数学関数技術仕様TS 18661-4aが統合されました。
定数式の認識の改善: constexpr記憶クラス指定子とともに、オブジェクト定義のためのconstexpr指定子が追加され、定数式として認識されるものが改善されました。
他にも様々な変更: その他にも、ビット単位の整数型 _BitInt(N)、nullptr定数、nullptr_t型、__VA_OPT__指定子、可変修飾型のサポート、#embedの導入、__has_include機能の追加、#elifdefおよび#elifndef条件付きインクルードプリプロセッサディレクティブの追加など、さまざまな変更が行われています。
これらの変更は、C言語の標準化において、より使いやすく、柔軟性が高く、規格の一貫性が向上することを目的としています。
C23の変更点のうちでも目立ったものを列挙します[https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf#page=688 N3096 Annex M (informative) Change History]。
bool,static_assert,true,false,thread_localがマクロからキーワードに昇格しました。
また、新旧のキーワードをマクロとして定義することで、プログラムの移行を容易にすることができるようになりました。
多くの _ で始まるキーワードがマクロになりましたが、全てではありません。
整数の幅の制約と時代遅れの符号表現（いわゆる「1の補数」と「符号-マグニチュード」）を削除しました。
static_assertの第二引数はオプショナルになりました。
識別子リストによる関数定義のサポートを削除しました。
関数宣言の引数リストが空の場合、voidを1つだけ含む引数リストと同じように扱うことが義務付けられました。
拡張月名フォーマット追加
gmtime_r,  localtime_r,  memccpy,  strdup,  strndup を統合。
最高精度の浮動小数点数を有効数字すべてを表現するために必要な 10 進数字の最小桁数を表すマクロ DECIMAL_DIG が廃止されました。DR 501
アップグレードや移植を支援するための変更を含むライブラリヘッダーに、バージョンテスト用マクロが追加されました。
この機能がサポートされていること自身を、まず STDC_VERSION__ マクロで確認する必要があります。
宣言の前や複合文の末尾にラベルを配置できるようにしました。
deprecated: 将来使用しないことを示すエンティティをマークする。
fallthrough: switchやlabelのフォールスルーが偶発的ではなく、意図的である場合を明示的にマークする。
maybe_unused: 最終的に使用されないかもしれない実体をマークする。
nodiscard: 使用された場合、その値がプログラムによって何らかの方法で処理されるべきエンティティをマークする。
reproducible: （再現可能）同じ入力が与えられると常に予測可能な出力を生成する関数タイプ(例えば、キャッシュされたデータ)をマークするため、しかしそのような関数の呼び出しの順序は依然として重要である。
unsequenced: 常に予測可能な出力を生成し、他のデータへの依存性がない関数タイプ（およびその他の関連する注意事項）をマークするためのものです。
noreturn: 関数が決して戻ってこないことを示す。
u8文字列プリフィックスとの整合性の為、u8文字プリフィックスが追加されました。
u8，u，Uをプリフィックスとする文字列を、それぞれ ISO/IEC 10646で定義された UTF-8，UTF-16，UTF-32とすることをが義務付けられました。
文字列と文字のためのリテラル、ワイドリテラル、UTF-8リテラル、UTF-16リテラル、UTF-32リテラルエンコーディングを分離し、これらの実行ベースバージョン、特に実行とワイド実行エンコーディングを単独で持つようになりました。
ヘッダー に欠落していた mbrtoc8 と c8rtomb 関数が追加されました。
複合リテラル( ''compound literals'' )には、型の一部としてストレージクラス指定子を含めることができ、複合リテラルのライフタイムを変更することができます。
複合リテラルのライフタイムを変更する（定数式に変更する場合もある）。
C23のconstexprは、新たに導入された記憶クラス指定子であり、オブジェクトの値をコンパイル時に固定するために使用されます。以下はその主な制約と意味です：
constexprで宣言されたオブジェクトやそのメンバーは、アトミック型、可変修飾型、またはvolatileやrestrict修飾子を持つ型を持つことができません。
浮動小数点数型の初期化子は、翻訳時の浮動小数点環境で評価されなければなりません。
constexprで宣言されたポインタ、整数、算術型のオブジェクトは、それぞれnull、整数定数式、算術定数式、または浮動小数点数のいずれかで初期化されなければなりません。
constexprで宣言されたオブジェクトの値は、コンパイル時に永久的に固定されます。
constexprで宣言されたオブジェクトは、暗黙的に定数修飾されます。
constexprはコンパイル時の計算や値の固定化に役立ちます。
typeof および typeof_unqual は、C言語の新しい演算子です。
これらの演算子は、指定された式や型名に基づいて、型情報を取得するために使用されます。
以下に、それぞれの演算子の概要を説明します：
typeof 演算子は、指定された式または型名の型を取得します。
式が与えられた場合、その式の型が返されます。
型名が与えられた場合、その型の情報が返されます。
例えば、typeof(1 + 1) は式 1 + 1 の型を取得します。
typeof_unqual 演算子は、typeof 演算子と同様に動作しますが、修飾を削除した型情報を返します。
つまり、const や volatile などの修飾子が削除された型情報が返されます。
例えば、typeof_unqual(const int) は int の型情報を返します。
これらの演算子は、特にマクロの定義や、型を動的に取得する必要がある場合などに役立ちます。
typeof 演算子は C 言語の柔軟性を高め、より効率的なコードを記述するのに役立ちます。
タグの互換性ルールに若干の変更が加わり、既存の矛盾を解消し、マクロを用いた汎用的なプログラミングを容易にし、代数的な型の構築を可能にすることができるようになりました。N2863 N2366 N2105
_BitIntは、ビット精度を指定するための型指定子です。指定されたビット数の整数型を表します。
以下に、_BitIntの使用例を示します。
int main() {
    _BitInt(8) byte;  // 8ビット整数型の変数byteを定義
    _BitInt(16) halfWord;  // 16ビット整数型の変数halfWordを定義
    _BitInt(32) word;  // 32ビット整数型の変数wordを定義
    byte = 255;  // byteに255を代入
    halfWord = 65535;  // halfWordに65535を代入
    word = 4294967295;  // wordに4294967295を代入
    printf("Byte: %d\n", byte);
    printf("Half Word: %d\n", halfWord);
    printf("Word: %d\n", word);
    return 0;
}
 
この例では、_BitIntを使用して8ビット、16ビット、32ビットの整数型を宣言し、それぞれの変数に値を代入しています。_BitIntを使用することで、特定のビット幅を持つ整数型を明示的に指定することができます。
この型の顕著な特性の1つは、性能上の理由から、デフォルトの整数プロモ ーションが行われないことです。
リテラル・サフィックス wb を使用することで、_BitInt とリテラルを含む式の不要な変換をさらに減らすことができます。N2960 N2946 N2775 N2709 N2646
列挙型に基礎となる型を指定する機能が追加されました。
これによって、int よりも大きな範囲の値表現を持つことができるようになりました。
enum Colour : char {
  Red, 
  Green,
  Blue
};
ヘッダー  が追加されました。
ビットおよびバイトを扱う一連のユーティリティを追加し、多くの実装の最も効率的な機能へポータブルにアクセスできるようにしました。
QCharやQVoidは、N3054には観られましたがN3096には見当たりません
既存関数の宣言を変更し、関数内に配置された型の定数性( ''const-ness'' )を保持するようになりました。N2973
QVoid *memchr(QVoid *s, int c, size_t n);
QChar *strchr(QChar *s, int c);
この変更は、Nプロポーザル N2522， 2603およびN2973 で提案されました。
この提案は、C標準ライブラリに含まれる12の検索関数（bsearch bsearch_s memchr strchr strpbrk strrchr strstr wcschr wcspbrk wcsrchr wcsstr wmemchr）が、const修飾子を失うという問題を解決するものです。これらの関数は、検索されるバッファへのconst修飾ポインタを受け取りますが、const修飾を失ったポインタを返します。提案では、これらの関数が、入力バッファの修飾子と同じ修飾子を持つ要素を返すことが明示的に指定されるべきであるとされています。つまり、ユーザーが指定した修飾子と同じ修飾子を持つ要素を返すことで、入力バッファのconst修飾を無意識に失うことを防ぐことができます。
提案の根拠として、既存のAPIはC11がジェネリックでオーバーロードされた関数の定義を導入する前に設計され、ライブラリに追加されました。したがって、入力パラメータには暗黙的にconst修飾を追加することができるため、const修飾されたバッファと変更可能なバッファの両方を検索することができるように、既存のシグネチャが設計されました。正しく使用されれば、返されるポインタの修飾が不足している場合でも、適切に修飾された結果ポインタに割り当てることで、同じ修飾が復元されます。これにより、検索関数はジェネリックな機能を提供する原始的な形式を提供します。
しかし、ユーザーが返されたポインタの変数が正しいタイプであることを手動で確認する必要があります。ユーザーがconst修飾されたバッファを検索して、結果を変更可能なオブジェクトのポインタに割り当てた場合、APIには直接的にこれがタイプエラーであることを伝える方法がありません。実装によっては、警告を表示することができるかもしれませんが、これは言語で伝えられるものを超えて、ライブラリ関数とその契約に関するハードコーディングされた知識を必要とするでしょう。
プリプロセッサディレクティブ #embed が追加された。
バイナリーデータを可能な限り忠実に埋め込む機能
nullptr定数とnullptr_t型が追加されました。
voidへのポインタと同じように定義された基本表現を持ちます。N3042
__VA_OPT__ は、マクロのパラメーターとして受け取った可変引数が空でない場合に置換するトークンを指定します。C++20
可変モディファイ型( ''Variably-Modified Types'' )のサポートを義務付けられました（ただし、可変長配列そのものではありません）。N2992
void foo(int n, double (*x)[n]) {
  (*x)[n] = 1; // 無効なアクセスは実行時に検出することができます
               // （場合によっては、より強力な解析によりコンパイル時にも検出可能） 
}
関数定義の引数の省略記号( ... )は、関数のパラメーターリストにおいて先行するパラメータなしで現れることができるようになりました。
va_startはもはやそのような引数が渡されることを必要としません。
Unicode 識別子が、UAX(Unicode Standard Annex) #31 に従うようになりました。
[TODO:#ハイライトの完成]
ANSI Cのプロトタイプ宣言以前の、K&R1形式の関数宣言が廃止されました。
K&R1形式の main():
int main(argc, argv)
    int argc;
    char *argv[];
{
    printf("Hello world!\");
}
を ??= の３文字で表すトリグラフ（JIS語では「3文字表記」）が規格から削除されました。C++では既にC++17で削除されています。
「C言語から2の補数以外の符号表現を削除することで、整数型の仕様を大幅に簡素化することができる」とし「他の符号表現の仕様」を排除しました。
二進数リテラルが追加されました。二進数リテラルは、接頭辞0bまたは0Bの後に0または1の数字が連続したものです。C++では既にC++14で二進数リテラルが導入されています。
二進数リテラルに呼応する形でprintf系とscanf系の関数に書式 %b が追加されました。
属性( ''attribute'' )は、一般化された構文を持つ言語エンティティに、開発者が各機能のために新しい構文やキーワードを導入する代わりに、追加の情報を付加できるメカニズムです。
[TODO:具体例]
型推論( ''Type inference; TI'' )とは、宣言がその初期化子として使用される式から型を推論することを可能にする機能です。
N3007提案では、auto i = 123L; の様に「型」の部分に auto と書くと初期化子（この場合は 123L）から変数（この場合は i）の型（この場合は long）を言語処理系が推論するという構文です（概ねC++と同じですが、C++には参照やラムダ式があるので若干事情が違います）。
auto は今までもキーワードでしたが、（静的変数に対して）「自動変数」を宣言することを表すもので、省略可能でした。
auto-example.c:
int main() {
  auto fname = "/etc/hosts";
  auto file = fopen(fname, "r");
  if (file == NULL) {
    perror(fname);
    return 1;
  }
  // ファイルから1行ずつ読み込んで標準出力に表示
  char line[256];
  for (auto i = 1; fgets(line, sizeof(line), file); i++) {
    printf("%03d: %s", i, line);
  }
  fclose(file);
  return 0;
}
この例の
  auto fname = "/etc/hosts";
  auto file = fopen(fname, "r");
    ...
  for (auto i = 1; fgets(line, sizeof(line), file); i++) {
は、これまでならば
  const char *fname = "/etc/hosts";
  FILE *file = fopen(fname, "r");
    ...
  for (int i = 1; fgets(line, sizeof(line), file); i++) {
と書くところですが、型推論を使い型名を明示しないで済んでいます。