はじまり
C言語は1972年頃、Dennis M. Ritchieが主体となって開発しました。C言語は高水準言語の中でも高速で、実行速度性能が要求されるソフトウェアの開発に用いられることが多いです。またポインターにより任意のアドレスを直接参照できたりビット単位で演算できたりなど、ハードウェア寄りの記述も可能となっています。これにより、組み込みソフトの分野でも多く使われています。
K&R
1978年にBrian W. KernighanとDennis M. Ritchieの共著で「The C Programming Language」が出版されました。著者名の頭文字から、しばしばK&Rと略されています。
その後標準ができるまで、実質的なC言語の標準として参照されてきました。しかしC言語は発展可能な言語であり、本書の記述も発展の可能性のある部分は厳密な記述をしていませんでした。この様なこともあり、C言語は普及するとともに互換性のない処理系が数多く誕生していきました
ISO/IEC 9899:1990(通称C89/C90)
ISOとANSI(American National Standards Institute:アメリカ規格協会)が共同でC言語の標準化を進めた結果、定められたのが本規格です。
また標準化を進める一方で、処理系依存とすることも一部で認められています。この最たるものが型のサイズで、各型のバイトはsizeof演算子で取得し、各型の最小値・最大値は<limits.h>で定義されているマクロ定数を参照することとされています。
ISO/IEC 9899/AMD1:1995(通称C95)
主に下記のような変更が行われました。
- <wchar.h>、<wctype.h>により、マルチバイト文字およびワイド文字への対応が追加されました。
- <iso646.h>により、マクロ化された演算子を使えるようになりました。(「&&」⇒「and」など)
ISO/IEC 9899:1999(通称C99)
主に下記の様な変更が行われました。
- ローカル変数の宣言がブロックの先頭でなくてもよくなりました。
- 少なくとも64ビットの整数値を保持できるlong long int型が追加されました。
- 可変長配列が導入されました。(厳密には可変長ではありませんが)
void func(int n) {
int a[n];
...
}
- <stdbool.h>により、bool型を使えるようになりました。
- <stdint.h>により、固定幅の整数型を使えるようになりました。
- <complex.h>により、複素数型を使えるようになりました。
- C++と同じく、「//」による1行コメントを使えるようになりました。
- 配列や構造体の指示初期化子が追加されました。
int a[10] = { [0] = 1, [9] = 1 }; // 指定しなかった領域は0となる
- インライン関数が追加されました。
- __func__マクロが追加されました。
ISO/IEC 9899:2011(通称C11)
主に下記の様な変更が行われました。
- <stdalign.h>により、アライメントの取得や設定を行えるようになりました。
- <stdnoreturn.h>により、_Noreturn関係指定子を使えるようになりました。
- <uchar.h>により、UTF-16とUTF-32用のchar16_t型とchar32_t型を使えるようになりました。なおUTF-8はchar型で代用します。
char16_t a = u'あ';
char32_t b = U'あ';
- <threads.h>、<stdatomic.h>により、マルチスレッドがサポートされるようになりました。
- _Genericによる総称選択を行えるようになりました。これにより、マクロが型に合わせて関数を呼び分けることが可能となりました。
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
- rsize_t型とRSIZE_MAXマクロが追加されました。
これまでsize_t型が用いられてきましたが、これは符号なしの整数型で非常に大きな値までカバーしています。これに対してrsize_t型は、RSIZE_MAXマクロの値以下であると規定されています。 - gets関数を削除し、代替としてgets_s関数が追加されました。
- <assert.h>に静的アサーション(static_assert)が追加されました。
// 式がゼロ(false)のとき、後方の文字列を表示してコンパイルは失敗する
static_assert(sizeof(int)==4,"Expecting 32 bit integers");
ISO/IEC 9899:2018(通称C17/C18)
不具合修正のみのマイナーバージョンアップです。
バージョンの確認方法
C95以降であれば、「__STDC_VERSION__」によりどのバージョンの規格に準拠しているかを確認することができます。
#ifdef __STDC_VERSION__
#if __STDC_VERSION__ == 201710L
printf("C17 に準拠しています\n");
#elif __STDC_VERSION__ == 201112L
printf("C11 に準拠しています\n");
#elif __STDC_VERSION__ == 199901L
printf("C99 に準拠しています\n");
#elif __STDC_VERSION__ == 199409L
printf("C95 に準拠しています\n");
#else
printf("不明な結果です:__STDC_VERSION__ = %ld\n", __STDC_VERSION__);
#endif
#else
printf("__STDC_VERSION__ が定義されていません\n");
#endif
- 処理系によっては「__STDC_VERSION__」が定義されていないこともあります。参考程度にみてください。なお次期C言語の規格(C2x)は「202311L」になる計画です。
- 処理系によっては、新しいC言語の規格制定前に一部の機能に先行で対応している場合があります。このためC99準拠だからといってC11の機能は何も使えないのかというと、それは調べてみないとわからないということになります。
- 結局のところ、何もかも処理系依存です。一般的に最新のC準拠でコーディングすることが望ましいとされていますが、複数の処理系を使用している場合は、コードの流用性を考えると踏み切りにくいところがあります。