この章では、プログラミング言語Cの歴史をたどり、ISO規格の進化や『プログラミング言語C』の各版の寄与を明らかにします。初期のCから現代の標準まで、言語機能や設計思想の変遷を探り、読者に深い理解を提供します。
C言語は、1972年にデニス・リッチーとケン・トンプソンによってベル研究所で開発されました。以後、C言語は数十年にわたり進化し、標準化されてきました。以下はC言語の主な仕様の変遷です。
最初のC言語仕様で、ブライアン・カーニハンとデニス・リッチーによる書籍 "The C Programming Language"（通称K&R C;邦題『プログラミング言語C』）の初版 で紹介されました。このバージョンは標準化されていませんでしたが、Cの基本的な特徴が確立されました。
標準ライブラリの限定: K&R Cの初期のバージョンでは、標準ライブラリが非常に限定されていました。基本的な入出力関数やメモリ管理関連の関数が提供されていましたが、後のバージョンと比較して機能が制限されていました。
基本的なデータ型: K&R Cは、基本的なデータ型（int、char、floatなど）をサポートしており、これらの型を使用して変数や関数を宣言できました。ただし、後のバージョンとは異なり、標準のvoid型が存在していませんでした。
制御構造: K&R Cは、基本的な制御構造（if、while、forなど）をサポートしていました。制御構造の文法は、後のバージョンと類似していますが、いくつかの微細な差異がありました。
ポインタとアドレス演算子: ポインタ機能は早い段階から存在しており、アドレス演算子 & と間接参照演算子 * を使用してメモリのアドレスやその値にアクセスできました。ポインタの扱いは後のバージョンと同様に重要でした。
構造体: K&R Cでは、構造体が導入され、ユーザーが複数の異なるデータ型をまとめるために使用できました。これにより、複雑なデータ構造を作成する能力が向上しました。
K&R CはC言語の初期の形態を示しており、その後の標準化プロセスでいくつかの変更が行われています。後のバージョンでは、機能の追加や改善が行われ、より広範なプログラミングニーズに対応するようになりました。
1989年に米国標準協会（ANSI）によって標準化されました。これにより、C言語は初めて公式に標準仕様を持つこととなりました。このバージョンはISOでも標準化され、C89またはC90として知られています。
// K&R C
int add(a, b)
    int a, b;
{
    return a + b;
}
// ANSI C
int add(int a, int b)
{
    return a + b;
}
新しいデータ型: ANSI Cでは新しいデータ型が導入されました。例えば、void型やlong double型などが追加されました。これらの新しい型がコード内で使用されている場合、適切に修正する必要があります。
新しいキーワード: ANSI Cでは新しいキーワードが導入されました。これにはconst、volatile、signed、unsignedなどが含まれます。これらのキーワードは変数の修飾や型指定に使用されます。
ヘッダーとライブラリ: ANSI Cでは新しいヘッダーやライブラリが導入され、標準ライブラリが拡張されました。コード内で新しい関数やヘッダーを使用している場合、これらを正しく取り込む必要があります。
可変引数関数: ANSI Cでは、可変引数関数の宣言や呼び出しにおいて、ヘッダーが必要です。これは、va_start、va_arg、va_endなどの関数が含まれています。
1999年にISOで標準化されたCの改訂版。新しい機能が導入され、標準ライブラリが拡張されました。代表的な変更に、可変長引数関数、複数の宣言を1つの文で行えるようにするブロック内の変数宣言などがあります。
C90からC99への移行では、いくつかの新しい機能が導入されているため、以下はその注意点です。
C99では、可変長配列（Variable Length Array, VLA）が導入されました。これは、実行時にサイズが決まる配列で、動的にメモリを確保する必要がない点が異なります。自動変数なのでスコープは定義されたブロック（通常は関数）で、確保されるのはスタック上なので、特に再帰を行うような場合はスタックオーバーフローに注意が必要です。
// C99
void processArray(int size) {
    int myArray[size];  // 可変長配列
    // 配列の処理
}
複合リテラル（Compound Literals）は、任意の型の一時的なオブジェクトを作成するための機能で、リテラルの一種です。この機能により、式の結果として生成された一時的な複合型のオブジェクトに対して、直接リテラルで初期化を行うことができます。
// C99以降
// (type-name) { initializer-list }
// 例
int main() {
    // int型の複合リテラル
    int array[] = {1, 2, 3};
    int *ptr = (int[]){4, 5, 6};
    // 構造体型の複合リテラル
    struct Point {
        int x;
        int y;
    };
    struct Point p = (struct Point){.x = 10, .y = 20};
    return 0;
}
この例では、int型と構造体型の複合リテラルを使用しています。複合リテラルは、配列や構造体の初期化、動的メモリ割り当てなどで利用されることがあります。また、ポインタを介して複合リテラルで初期化されたオブジェクトにアクセスすることも可能です。
// C99
inline int add(int a, int b) {
    return a + b;
}
// C99 行コメント
// C99
int myArray[] = {1, 2, [5] = 10, 20};
C99では、ブロック内での変数宣言が、ブロックの先頭ではなく、どこでもできるようになりました。
// C99
int32_t myInt = 42;
2011年にISOで標準化されたC言語の次のバージョン。新しい機能や改良が導入され、マルチスレッドプログラミングをサポートするスレッドサポートライブラリ（Thread Support Library）が導入されました。
C99からC11への移行は、C言語の新しい標準であるC11で導入された機能や変更を考慮する必要があります。以下は、C99からC11への移行の注意点のいくつかです：
新しいキーワードと機能: C11では、新しいキーワードや機能が導入されています。例えば、_Alignasや_Alignof、_Noreturnなどがあります。これらのキーワードや機能がコード内で使用されている場合、適切に修正する必要があります。
// C11
_Static_assert(sizeof(int) == 4, "int must be 4 bytes");
// C11
int main() {
    print_value(42);    // int
    print_value(3.14);  // double
    return 0;
}
// C11
_Atomic int counter = ATOMIC_VAR_INIT(0);
atomic_fetch_add(&counter, 1);
C11では、Unicodeサポートが向上し、新しいエスケープシーケンスが導入されました。これにより、Unicode文字やエスケープシーケンスをより直感的に扱うことができます。
// C11
char japanese[] = u8"日本語";  // UTF-8エンコード
策定中の ISO/IEC 9899:2023（通称C2xまたはC23）での現在知りうる変更点の一部。
識別子リストによる関数定義のサポートを削除し、プロトタイプ宣言が必須化されました。
関数宣言の引数リストが空の場合、voidを1つだけ含む引数リストと同じように扱うことが義務付けられました。
strftime関数に拡張月名フォーマットが追加されました。
いくつかの関数（gmtime_r, localtime_r, memccpy, strdup, strndup）が統合されました。
バイナリ浮動小数点技術仕様 TS 18661-1、10進浮動小数点技術仕様書 TS 18661-2、数学関数技術仕様書 TS 18661-4a の統合が行われました。
DECIMAL_DIG マクロが廃止されました。
bool, static_assert, true, false, thread_local がマクロからキーワードに昇格しました。
新旧のキーワードをマクロとして定義することで、プログラムの移行を容易にすることができるようになりました。
ANSI Cのプロトタイプ宣言以前の、K&R1形式の関数宣言が廃止されました。
# を ??= の３文字で表すトリグラフ（JIS語では「3文字表記」）が規格から削除されました。
整数の符号表現が二の補数に限定され、他の符号表現の仕様が削除されました。
二進数リテラルが導入され、接頭辞 0b または 0B の後に0または1の数字が連続したものが使用できるようになりました。
二進数リテラルに対応する形で、printf系とscanf系の関数に書式 %b が追加されました。
static_assert の第二引数がオプショナルになりました。
属性（attribute）に関する構文と種類が規格化され、開発者が言語エンティティに追加の情報を付加できるようになりました。
オブジェクト定義における型推論が規格化され、auto キーワードを使用して初期化子から変数の型を推論できるようになりました。
可変モディファイ型のサポートが義務付けられました（ただし、可変長配列そのものではありません）。
関数定義の引数の省略記号 ... が、関数のパラメーターリストにおいて先行するパラメータなしで使用できるようになりました。
複合リテラルには、型の一部としてストレージクラス指定子を含めることができ、複合リテラルのライフタイムを変更することが可能になりました。
ライブラリヘッダーに、アップグレードや移植を支援するためのバージョンテスト用マクロが追加されました。
宣言の前や複合文の末尾にラベルを配置できるようになりました。
deprecated, fallthrough, maybe_unused, nodiscard, reproducible, unsequenced, noreturn などの属性を含むアトリビュート機能が追加されました。
u8文字列プリフィックスが追加されました。
u8, u, Uをプリフィックスとする文字列を、それぞれ ISO/IEC 10646 で定義された UTF-8, UTF-16, UTF-32 とすることが義務付けられました。
文字列と文字のためのリテラル、ワイドリテラル、UTF-8リテラル、UTF-16リテラル、UTF-32リテラルエンコーディングが分離され、それぞれの実行ベースバージョンが単独で持つようになりました。
ヘッダー  に欠落していた mbrtoc8 と c8rtomb 関数が追加されました。
オブジェクト定義に constexpr 指定子を追加し、constexpr ストレージクラス指定子と組み合わせて定数式として認識される内容が改善されました。
式の型を推論する typeof と typeof_unqual 演算子が追加されました。
タグの互換性ルールに変更が加わり、既存の矛盾を解消し、マクロを用いた汎用的なプログラミングを容易にし、代数的な型の構築を可能にすることができるようになりました。
ビット精度の整数型 _BitInt が追加されました。
列挙型に基礎となる型を指定する機能が追加されました。
既存関数の宣言が変更され、関数内に配置された型の定数性(const-ness)を保持するようになりました。
プリプロセッサディレクティブ #embed が追加され、バイナリーデータを可能な限り忠実に埋め込む機能が提供されました。
nullptr 定数と nullptr_t 型が追加されました。
__VA_OPT__ は、マクロのパラメーターとして受け取った可変引数が空でない場合に置換するトークンを指定します。
可変モディファイ型(Variably-Modified Types)のサポートが義務付けられました。
Unicode 識別子が、UAX(Unicode Standard Annex) #31 に従うようになりました。
C言語のキーワードは、言語の進化や新しい機能の導入に伴って変わってきました。以下に、主なC言語の標準ごとのキーワードの変遷を示します。ただし、すべてのキーワードや変更点を網羅するわけではありません。
K&R C (1972年): 最初のC言語仕様では、基本的なキーワードのセットが導入されました。代表的なものとして、int、char、for、if、whileなどがあります。
ANSI C (C89/C90、1989年): ANSI Cの導入に伴い、新しいキーワードが追加されました。代表的なものとして、void、const、volatileなどが挙げられます。
ISO/IEC C99 (1999年): C99では、新しいキーワードが導入されました。代表的なものに、inline、_Bool、restrict、_Complex、_Imaginaryなどがあります。
ISO/IEC C11 (2011年): C11では、新しいキーワードが導入され、様々な機能が拡張されました。代表的なものに、_Alignas、_Alignof、_Atomic、_Noreturn、_Static_assertなどがあります。
将来のバージョン: 将来のC言語のバージョンでは、新しい機能や拡張が導入され、それに伴い新しいキーワードが追加される可能性があります。新しい標準の策定プロセスで提案された機能が取り込まれることで、言語の進化が続きます。
C言語のキーワードの変遷は、言語の進化によって柔軟性や表現力が向上しています。新しいキーワードを使用することで、より効率的なコーディングや新しいプログラミングスタイルを採用することができます。