C言語/C23の変更点
2023年11月現在の最新のCの国際規格ISO/IEC 9899:2018(通称C17)は、ISO/IEC 9899:2011(通称C11)の不明確な部分を補うErrata的な規格で、実質的にC11が現行の最新規格という状態が10年以上続いています。
このような中、
ここでは、現在入手可能な working draft — September 3, 2022 ISO/IEC 9899:2023 (E)N3054,N3096[2]に基づいて、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
指定子が追加され、定数式として認識されるものが改善されました。 - 修飾子を保存する標準ライブラリ関数: const属性が静かに失われることを避けるための
QVoid
およびQChar
の導入。 - 他にも様々な変更: その他にも、ビット単位の整数型
_BitInt(N)
、nullptr
定数、nullptr_t
型、__VA_OPT__
指定子、可変修飾型のサポート、#embed
の導入、__has_include
機能の追加、#elifdef
および#elifndef
条件付きインクルードプリプロセッサディレクティブの追加など、さまざまな変更が行われています。
これらの変更は、C言語の標準化において、より使いやすく、柔軟性が高く、規格の一貫性が向上することを目的としています。
ハイライト[編集]
C23の変更点のうちでも目立ったものを列挙します[3]。
キーワードに昇格したマクロ[編集]
bool
,static_assert
,true
,false
,thread_local
がマクロからキーワードに昇格しました。
また、新旧のキーワードをマクロとして定義することで、プログラムの移行を容易にすることができるようになりました。
多くの _ で始まるキーワードがマクロになりましたが、全てではありません。
整数は二の補数表現が必須[編集]
整数の幅の制約と時代遅れの符号表現(いわゆる「1の補数」と「符号-マグニチュード」)を削除しました。
static_assertの一引数版[編集]
static_assert
の第二引数はオプショナルになりました。
プロトタイプ宣言が必須化[編集]
識別子リストによる関数定義のサポートを削除しました。
空の引数リストの意味がC++と同じに[編集]
関数宣言の引数リストが空の場合、voidを1つだけ含む引数リストと同じように扱うことが義務付けられました。
ISO/IEC 9945 (POSIX)との整合性の向上[編集]
strftime[編集]
拡張月名フォーマット追加
関数の統合[編集]
gmtime_r
, localtime_r
, memccpy
, strdup
, strndup
を統合。
浮動小数点規格IEC 60559との整合性の向上[編集]
- バイナリ浮動小数点技術仕様 TS 18661-1 の統合
- 10進浮動小数点技術仕様書 TS 18661-2 の統合
- 数学関数技術仕様書 TS 18661-4a の統合
DECIMAL_DIG廃止[編集]
最高精度の浮動小数点数を有効数字すべてを表現するために必要な 10 進数字の最小桁数を表すマクロ DECIMAL_DIG が廃止されました。DR 501
ライブラリーヘッダーにバージョンテスト用マクロを追加[編集]
アップグレードや移植を支援するための変更を含むライブラリヘッダーに、バージョンテスト用マクロが追加されました。 この機能がサポートされていること自身を、まず STDC_VERSION__ マクロで確認する必要があります。
ラベル配置可能位置の拡大[編集]
宣言の前や複合文の末尾にラベルを配置できるようにしました。
属性を含むアトリビュート機能を追加[編集]
- deprecated
- 将来使用しないことを示すエンティティをマークする。
- fallthrough
- switchやlabelのフォールスルーが偶発的ではなく、意図的である場合を明示的にマークする。
- maybe_unused
- 最終的に使用されないかもしれない実体をマークする。
- nodiscard
- 使用された場合、その値がプログラムによって何らかの方法で処理されるべきエンティティをマークする。
- reproducible
- (再現可能)同じ入力が与えられると常に予測可能な出力を生成する関数タイプ(例えば、キャッシュされたデータ)をマークするため、しかしそのような関数の呼び出しの順序は依然として重要である。
- unsequenced
- 常に予測可能な出力を生成し、他のデータへの依存性がない関数タイプ(およびその他の関連する注意事項)をマークするためのものです。
- noreturn
- 関数が決して戻ってこないことを示す。
u8文字プリフィックス[編集]
u8文字列プリフィックスとの整合性の為、u8文字プリフィックスが追加されました。
u8, u, U文字列のエンコードの規格化[編集]
u8,u,Uをプリフィックスとする文字列を、それぞれ ISO/IEC 10646で定義された UTF-8,UTF-16,UTF-32とすることをが義務付けられました。
エンコーディングの分離[編集]
文字列と文字のためのリテラル、ワイドリテラル、UTF-8リテラル、UTF-16リテラル、UTF-32リテラルエンコーディングを分離し、これらの実行ベースバージョン、特に実行とワイド実行エンコーディングを単独で持つようになりました。
uchar.hに関数を追加[編集]
ヘッダー<uchar.h> に欠落していた mbrtoc8 と c8rtomb 関数が追加されました。
複合リテラルのライフタイムの変更[編集]
複合リテラル( compound literals )には、型の一部としてストレージクラス指定子を含めることができ、複合リテラルのライフタイムを変更することができます。 複合リテラルのライフタイムを変更する(定数式に変更する場合もある)。
constexpr[編集]
C23のconstexpr
は、新たに導入された記憶クラス指定子であり、オブジェクトの値をコンパイル時に固定するために使用されます。以下はその主な制約と意味です:
constexpr
で宣言されたオブジェクトやそのメンバーは、アトミック型、可変修飾型、またはvolatile
やrestrict
修飾子を持つ型を持つことができません。- 浮動小数点数型の初期化子は、翻訳時の浮動小数点環境で評価されなければなりません。
constexpr
で宣言されたポインタ、整数、算術型のオブジェクトは、それぞれnull
、整数定数式、算術定数式、または浮動小数点数のいずれかで初期化されなければなりません。constexpr
で宣言されたオブジェクトの値は、コンパイル時に永久的に固定されます。constexpr
で宣言されたオブジェクトは、暗黙的に定数修飾されます。
constexpr
はコンパイル時の計算や値の固定化に役立ちます。
typeofとtypeof_unqual[編集]
typeof
および typeof_unqual
は、C言語の新しい演算子です。
これらの演算子は、指定された式や型名に基づいて、型情報を取得するために使用されます。
以下に、それぞれの演算子の概要を説明します:
- typeof:
typeof
演算子は、指定された式または型名の型を取得します。- 式が与えられた場合、その式の型が返されます。
- 型名が与えられた場合、その型の情報が返されます。
- 例えば、
typeof(1 + 1)
は式1 + 1
の型を取得します。
- typeof_unqual:
typeof_unqual
演算子は、typeof
演算子と同様に動作しますが、修飾を削除した型情報を返します。- つまり、
const
やvolatile
などの修飾子が削除された型情報が返されます。 - 例えば、
typeof_unqual(const int)
はint
の型情報を返します。
これらの演算子は、特にマクロの定義や、型を動的に取得する必要がある場合などに役立ちます。 typeof 演算子は C 言語の柔軟性を高め、より効率的なコードを記述するのに役立ちます。
タグの互換性ルールの改善[編集]
タグの互換性ルールに若干の変更が加わり、既存の矛盾を解消し、マクロを用いた汎用的なプログラミングを容易にし、代数的な型の構築を可能にすることができるようになりました。N2863 N2366 N2105
ビット精度の整数型 _BitInt の追加[編集]
_BitInt
は、ビット精度を指定するための型指定子です。指定されたビット数の整数型を表します。
以下に、_BitInt
の使用例を示します。
#include <stdio.h> 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
enum の基礎となる型が指定可能に[編集]
列挙型に基礎となる型を指定する機能が追加されました。 これによって、int よりも大きな範囲の値表現を持つことができるようになりました。
enum Colour : char { Red, Green, Blue };
stdbit.h[編集]
ヘッダー <stdbit.h> が追加されました。 ビットおよびバイトを扱う一連のユーティリティを追加し、多くの実装の最も効率的な機能へポータブルにアクセスできるようにしました。
QCharやQVoidの導入[編集]
既存関数の宣言を変更し、関数内に配置された型の定数性( 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[編集]
プリプロセッサディレクティブ #embed
が追加された。
バイナリーデータを可能な限り忠実に埋め込む機能
nullptr定数とnullptr_t型を追加[編集]
nullptr定数とnullptr_t型が追加されました。 voidへのポインタと同じように定義された基本表現を持ちます。N3042
__VA_OPT__[編集]
__VA_OPT__ は、マクロのパラメーターとして受け取った可変引数が空でない場合に置換するトークンを指定します。C++20
可変モディファイ型のサポートが義務化[編集]
可変モディファイ型( Variably-Modified Types )のサポートを義務付けられました(ただし、可変長配列そのものではありません)。N2992
void foo(int n, double (*x)[n]) { (*x)[n] = 1; // 無効なアクセスは実行時に検出することができます // (場合によっては、より強力な解析によりコンパイル時にも検出可能) }
関数の第一引数に ... が使用可能に[編集]
関数定義の引数の省略記号( ... )は、関数のパラメーターリストにおいて先行するパラメータなしで現れることができるようになりました。 va_startはもはやそのような引数が渡されることを必要としません。
Unicode 識別子更新[編集]
Unicode 識別子が、UAX(Unicode Standard Annex) #31 に従うようになりました。
[編集]
[編集]
[編集]
[編集]
[TODO:#ハイライトの完成]
C23の変更点[編集]
文書番号 | タイトル | 概要 |
---|---|---|
N2432 | Remove support for function definitions with identifier lists 旧式の関数定義の廃止 |
ANSI Cのプロトタイプ宣言以前の、K&R1形式の関数宣言が廃止されました。 |
N2940 | Remove Trigraphs??! トリグラフの削除 |
# を ??= の3文字で表すトリグラフ(JIS語では「3文字表記」)が規格から削除されました。C++では既にC++17で削除されています。
|
N2412 | Two’s complement sign representation for C2x 符号付き整数の形式は二の補数に限定 |
「C言語から2の補数以外の符号表現を削除することで、整数型の仕様を大幅に簡素化することができる」とし「他の符号表現の仕様」を排除しました。 |
N2549 | Binary Literals 二進数リテラル |
二進数リテラルが追加されました。二進数リテラルは、接頭辞0bまたは0Bの後に0または1の数字が連続したものです。C++では既にC++14で二進数リテラルが導入されています。 |
N2612 | Formatted input/output of binary integer numbers 二進整数の書式付き入出力 |
二進数リテラルに呼応する形でprintf系とscanf系の関数に書式 %b が追加されました。 |
N2335 | Attributes in C 属性 |
属性に関する構文と属性の種類が規格化されました。 |
N3007 | Type inference for object definitions 型推論 |
オブジェクト定義に於ける型推論が規格化されました。 |
旧式の関数定義の廃止[編集]
ANSI Cのプロトタイプ宣言以前の、K&R1形式の関数宣言が廃止されました。
- K&R1形式の main()
#include <stdio.h> int main(argc, argv) int argc; char *argv[]; { printf("Hello world!\"); }
トリグラフの削除[編集]
#
を ??=
の3文字で表すトリグラフ(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
#include <stdio.h> #include <stdlib.h> 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++) {
と書くところですが、型推論を使い型名を明示しないで済んでいます。
脚註[編集]
- ^ N3054によると、__STDC_VERSION__ は 202311L となるようです。
- ^ C23 now finalized!
- ^ N3096 Annex M (informative) Change History
外部リンク[編集]
- ISO/IEC WG 14 Document Log. ISO/IEC. (2022-09-29) .
- C2x: N3054 working draft — September 3, 2022 ISO/IEC 9899:2023 (E). ISO/IEC. (2022-09-03) .
- ISO/IEC 9899:2018(en) Information technology — Programming languages — C. ISO/IEC. (2018-07-05) .
- N2176 C17 ballot ISO/IEC 9899:2017. ISO/IEC JTC1/SC22/WG14. オリジナルの2018-12-30時点によるアーカイブ。 .