C言語
汎用プログラミング言語のひとつ
C言語︵シーげんご、英: C programming language︶は、1972年にAT&Tベル研究所のデニス・リッチーが主体となって開発した汎用プログラミング言語である。英語圏では﹁C language﹂または単に﹁C﹂と呼ばれることが多い。日本でも文書や文脈によっては同様に﹁C﹂と呼ぶことがある。制御構文などに高水準言語の特徴を持ちながら、ハードウェア寄りの記述も可能な低水準言語の特徴も併せ持つ。基幹系システムや、動作環境の資源制約が厳しい、あるいは実行速度性能が要求されるソフトウェアの開発に用いられることが多い。後発のC++やJava、C#など、﹁C系﹂と呼ばれる派生言語の始祖でもある[注釈1]。
![]() C言語のロゴ | |
パラダイム |
命令型プログラミング、構造化プログラミング、手続き型プログラミング ![]() |
---|---|
登場時期 | 1972年 . |
開発者 |
ベル研究所、デニス・リッチー、米国国家規格協会、国際標準化機構、ケン・トンプソン ![]() |
最新リリース | ISO/IEC 9899:2018/ 2018年 |
型付け | 弱い静的型付け |
主な処理系 | GCC, Clang, Visual C++, Intel C++ Compiler |
影響を受けた言語 |
ALGOL 68、B言語、アセンブリ言語、FORTRAN、PL/I、CPL、BCPL、ALGOL 60、ALGOL ![]() |
影響を与えた言語 | awk、csh、C++、Objective-C、Rust、D言語、Java、JavaScript、Limbo |
プラットフォーム |
Microsoft Windows、Unix系 ![]() |
ウェブサイト | |
拡張子 |
.c , .h |
特徴
編集この節に雑多な内容が羅列されています。 |
Cには他のプログラミング言語と比較して、特筆すべきいくつかの特徴がある。
利点
編集
●構造化プログラミングのパラダイムに対応した高水準の手続き型言語である。ハードウェアの直接的な制御ができる機能を備えつつ、機械語やアセンブリ言語︵アセンブラ︶のような低水準言語と比較して、ソースコードの再利用性やメンテナンス性に優れており、目的に応じたプログラムの変更や拡張が容易である。
●汎用性およびプログラムの自由度が高く、リソースや性能要求の厳しい用途にも耐えうるため、アプリケーションソフトウェアの開発だけでなく、オペレーティングシステム︵OS︶やデバイスドライバー、ファームウェアの記述、マイコン制御・機械制御など、上位層・下位層を問わず、あらゆる分野で利用されている。
●対応する機器の範囲が広い。パーソナルコンピュータやワークステーションはもちろん、自動車や家電の組み込み用マイコンからスーパーコンピュータまで、C言語を使用できるハードウェアは多様である。そのため、C言語のコード資産が蓄積されている環境・分野は多岐に渡る。
●商用・非商用を問わず、採用ソフトウェア分野が広い。プログラム作成やデバッグのための補助的なソフトウェア︵プログラミングツール︶が豊富である。
●ソースコードを機械語に変換するソフトウェア︵コンパイラ︶などの開発環境がCPUやOSに付属していたり無償だったりするものもあるため、ライセンス料の支払いをしなくても使用が始められる。
欠点
編集
●開発時期が古いことから、言語構文︵文法︶に機械語の影響が強く、仕様自体は単純ではあるが明快ではなく難解である。この欠点を改良するためのちに開発された後発言語に比較し、プログラマが記述しなければならないことが多く、低水準言語のように面倒で習得しにくい側面を持つ。
●Cは、移植の容易性、自由度、実行速度、コンパイル速度などを追求した。代わりにコンパイル後のコードの安全性を犠牲にしている。また、詳細を規格で規定せず処理系に委ねている部分が多く、Cで書かれたソフトウェアでは処理系依存のコードが氾濫する原因となった。セキュリティ上の脆弱性や潜在的バグによる想定外の動作、コンパイラによる最適化の難しさ[注釈2]といった問題を抱えており、最適化するとコンパイル速度が遅くなるなどの問題が生じることがある。
上記のように、利点でもあり、同時に欠点にもなる特徴を備えている。
もともとUNIXおよびCコンパイラの移植性を高めるために開発されてきた経緯から、オペレーティングシステム︵OS︶のカーネルおよびコンパイラ向けの低水準な記述ができるなど、ハードウェアをある程度抽象化しつつも、必要に応じて低水準言語と同じことを実現できるようなコンピュータ寄りの言語仕様になっている。そのため、低水準な記述ができる高水準言語と言われたり、高水準言語の顔をした低水準言語︵高級アセンブラ[2]、汎用アセンブラ[3]︶と言われたりすることがある。
Cはアマチュアからプロ技術者まで、プログラマ人口が多く、プログラマのコミュニティが充実している。使用者の多さから、正負の両面含め、Cはプログラミング文化に大きな影響を及ぼしている。また、多目的性と、対応機器の多彩さのため、﹁コンピュータを使ってやること﹂は大抵、Cで対応可能である。ただし、Cで効率的かつ安全に記述できるかどうかはまた別の話である。スクリプト言語やコマンドラインシェルを使えば手軽に実現にできるような処理まで、わざわざCで記述する必要はない。また、GUIアプリケーションフレームワークは、Cからは利用できず、統合開発環境と連携する新しいプログラミングツールやプログラミングパラダイムに対応した後発言語でなければ利用できないものもある。
MISRA CやCERT Cというコーディング標準︵コーディング規約︶を定義して、危険な機能の使用や記述を禁止するという制限を設けることでCを安全に利用するためのガイドラインが運用されている分野もある。特にプログラミングミスが人命に直結する自動車分野などでCを利用するには、このような制約が重要である。
機能と自由度
編集
●文の区切りを終端記号 セミコロン﹁
;
﹂で表し、改行文字にも空白にもトークンの区切りとしての意味しか持たせない﹁フリーフォーマット﹂という形式を採用している。中括弧{ }
によるブロック構造およびスコープをサポートする。
●ALGOLの思想を受け継いで構造化プログラミングに対応している。手順を入れ子構造で示して見通しの良い記述をすることができる。原理的に無条件分岐︵goto
︶を使用する必要はなく、MISRA Cでは当初goto文を禁止していた。
●モジュール化がファイルを単位として可能。モジュール内だけで有効な名前を使うことができるスコープを持っている。
●プログラムを戻り値つきのサブルーチンに分離できる。C言語ではこれを関数と呼び、関数内のプログラムコードでは、独立したスコープを持つ変数︵ローカル変数︶が使用できる。これにより、データの流れがブロックごとに完結するのでデバッグが容易になり、また関数の再帰呼び出しも可能となる。また、多人数での共同開発の際にも変数名の衝突が回避しやすくなる。なお、C言語ではUNIXのようなOSを前提としたホスト環境と、割り込み制御のようなOSを前提としないフリースタンディング環境とがある。ホスト環境では、プログラム開始直後に実行するプログラム要素を main
という名前の関数として定義する[注釈3]。プログラム中で再帰的にmain
関数を呼ぶことも可能︵C++では不可能[4][5]︶。フリースタンディング環境では、エントリーポイントと呼ばれるアドレスに置かれたコードをプログラムの開始点とするが、それがmain関数である必要はない。なお再帰呼び出しそのものは、スタックオーバーフローの原因となるため、MISRA Cでは禁止している。
●システム記述言語として開発されたため、高級言語であるがアセンブラ的な低水準の操作ができる。ポインタ演算、ビットごとの論理演算、シフト演算などの機能を持ち、ハードウェアに密着した処理を効率よく記述できる。これはオペレーティングシステムやデバイスドライバーなどを記述する上では便利であるが、注意深く利用しないと発見しにくいバグの原因となる。ライブラリ関数は、C言語規格が規定している関数と、OSが規定している関数との間の整合性、棲み分けなどが流動的である。MISRA Cのようないくつかの制約では、C言語規格が規定している関数の妥当性について指摘し、いくつかの関数を利用しないように規定している。
●ソースコードの記述に使う文字集合はANSI C (C89) およびISO/IEC 9899:1990 (C90) ではASCIIを標準としている。他のISO 646でも書けるように、3文字利用したトライグラフと呼ばれる表記法も存在する。その後、ISO/IEC 9899:1995 AMD (C95) などではマルチバイト文字セット対応の拡張を規定している。さらに、その後トライグラフは複数のコードを利用したシステムでしか利用がない[要説明]ため、より分かり易い2文字によるダイグラフを規定している。
●組み込みの整数型および浮動小数点数型のほか、構造体、共用体、列挙体︵列挙型︶によるユーザー定義のデータ型や列挙定数をサポートする。構造体および共用体はビットフィールドをサポートする。
アセンブラとのインタフェース
編集
●多くの処理系がインラインアセンブラを搭載しているほか、アセンブラで出力したオブジェクトとのリンクが容易になっている。これにより速度が要求される部分だけをアセンブリ言語で記述するということが容易に行えることが多い。アセンブラとのインタフェースは#pragma asmなどを用いて局所化を図る努力はあるが、コンパイラごとに定義があり、CPUが同一であっても移植性が低い場合がある。
コンパイラ仕様
編集
●コンパイラの処理が1パスで済む仕様になっている。歴史的な経緯から、変数の宣言において型指定がない場合は
int
型とみなし、関数の戻り値の型指定がない場合はint
型とみなす。ANSI C (C89) ではコンパイル時型検査の強化のために関数プロトタイプの機能が導入されたが、関数の宣言がない場合の戻り値はint
型とみなし、引数は未知︵任意︶とみなす。しかし、このような暗黙の型指定は型安全性を損ない未定義動作を引き起こす危険性があるため、ISO/IEC C:1999 (C99) 以降では暗黙の型指定に関する仕様が標準規格の文面から削除された。いずれも使用︵参照︶するより前に適切に宣言する必要がある。ClangやGCCといったC99準拠のコンパイラは、このような暗黙の型指定について、C99モードであってもC89互換の動作を残してはいるものの、非標準の動作であるため警告を出すようになっている。なお、関数宣言において()
のように引数を省略すると、引数を未知とする仕様はC99でも残されている。後継言語では完全なプロトタイプ宣言を必須とするか、あるいはプロトタイプ宣言自体を不要としているが、記述によっては先読みが必要になりうる。
●マクロ記述やコンパイル条件の指定などができる前処理指令が標準化されている。前処理指令の解釈をするプリプロセッサ (preprocessor) を持っている。プリプロセッサは、その名の通りコンパイル処理の前に自動的に実行される。コンパイラの機能として、プリプロセッサを通しただけの段階のソースコードを出力可能になっているものがある。前処理の結果を検査することで、設計者の意図と前処理の結果のずれがないか確認できる。
処理系の簡素化
編集
処理系の簡素化のため、以下のように安全性を犠牲にした仕様が多い。なお、ホスト環境やプログラムの内容によっては、以下に対して脆弱性対策を施したとしても実行速度の低下が無視できる程度であることも多く、言語仕様側の欠点とみなされることも少なくない。
配列参照時の自動的な添字のチェックをしない
これを要因とする代表的なバグが、固定長のバッファ領域をはみだしてデータの書き込みが行われてしまう﹁バッファオーバーフロー﹂︵バッファオーバーラン︶である。範囲外のアクセスは、書き込みだけでなく読み取りの場合も未定義動作を引き起こす。標準ライブラリにはバッファオーバーフローや範囲外アクセスを考慮していない関数があり、かつ多用されがちなため、しばしば脆弱性の原因となる。また、Cではプログラムにより明示的に制御︵動的メモリ確保︶することで可変長配列の実現を可能にしているが、確保した領域の範囲外にアクセスしても自動的な伸長は行なわれない。
後継言語では、標準ライブラリまたは組み込み型により可変長配列をサポートしていたり、範囲外アクセス時には例外︵実行時エラー︶を送出するなどして安全性を優先していたりすることが多い。
文字列を格納するための特別な型が存在しない
文字列には
char
型の配列を利用する。言語仕様上に特別な扱いはないが、ヌル文字︵'\0'
︶を終端とする文字列表現を使い、その操作をする標準ライブラリ関数がある。これは実質的にメモリ領域のポインタアクセスそのもので、固定長バッファに対して、それより長い可変長の文字列を書き込んでしまうことがあり、バッファオーバーランの元凶の1つとなっている。
後継言語では文字列処理を特に強化している場合が多く、標準ライブラリあるいは言語仕様による組み込みの文字列型を提供している。
自動変数の自動的な初期化をしない
自動変数︵静的でないローカル変数︶は変数の中でも最も頻繁に用いられる。初期化されていない変数を参照した場合、値は不定となるが、不定な値へのアクセスは未定義動作であるので、コンパイラ最適化の過程で想定しない形に改変することもある[6]。変数宣言・初期化の仕様による制限から、変数宣言の時点で初期化せず後で代入することで初期化に代えることが日常的で、誤って不定の値の変数を読み出すバグを作り込みやすい。なお自動変数の自動とは変数の領域の確保と解放が自動であるという意味であり、自動的に初期化されるという意味ではない。
後継言語では、明示的な初期化が記述されていない変数は、不定値ではなくその変数の型の既定値︵ゼロあるいはゼロ相当の値︶で初期化される仕様になっていることが多い。
その他
編集
●ソースコード上の文字の大文字・小文字を区別する。
●入出力や動的メモリ確保を含めほとんどの機能が、C言語自身で書かれたライブラリによって提供される。このことは、C言語の機種や環境依存性が低く、それらに依存する箇所をライブラリへ分離することにより移植性︵ポータビリティ︶が高いことを意味する[要出典]。さまざまな機種があるUNIXの世界でC言語が普及した理由のひとつである。
●例として、POSIX環境での動的メモリ確保は
malloc
およびその類似関数にて提供される。一方、カーネルではメモリ確保の際にスレッドがブロックされるとカーネル内のデータが他のスレッドにより変更され、予期せぬ動作を起こす恐れがあることや、メモリ内容の初期化が必要かどうかによって割当先のページを選択することによりシステムの効率が上がることから、多くの場合POSIXとは異なるAPIを使用している。Linuxカーネルの場合、前者はフラグGFP_KERNEL
とGFP_AT
OMIC
の使い分け、後者は関数kmalloc
︵割り当てたメモリの内容は不定︶とkzalloc
︵割り当てたメモリの内容はゼロクリア済︶の使い分けにより実装している[7]。
●プログラムの実行に必要とするハードウェア資源が、アセンブラよりは多いが他の高級言語より少なくてすむため、現在さまざまな電化製品などの組み込みシステムでも使用されている。
●組み込み向けの場合は、プログラミング言語として、アセンブラ以外ではCとC++しか用意されていないことがある。その場合、他のプログラミング言語は、CやC++で書かれた処理系が存在すればコンパイルすることにより利用可能となることもあるが、メモリ制約などで動作しないことがある。
●ANSI/ISOにより規格が標準化された後は言語仕様の変化が小さく安定していること、C言語のプログラマ人口やコード資産が多いこと、C++やObjective-CからC言語関数を直接利用できること、また必要に応じて他のプログラミング言語からC言語関数を呼び出すためのバインディングを記述することが容易であることなどから、APIの外部仕様としてC言語の関数インターフェイスが選ばれることが多い。例えばOpenGLやOpenCLのようなオープン規格は第一級言語としてC言語を採用している。
コード例
編集Hello worldプログラム
編集
C言語のHello worldプログラムは、ホスト環境を前提とするか、フリースタンディング環境を前提とするかで、方向性が異なる。ホスト環境を前提とする場合には、標準入出力の利用により、動作をすぐに確かめることができる。以下では、標準Cライブラリのヘッダ
st
dio.h
にて宣言されている、puts
関数あるいはprintf
関数を利用したものを例示する。
/* int puts(const char* s) を使う場合。 */
#include <stdio.h>
int main(void)
{
puts("Hello, world!");
return 0;
}
/* int printf(const char* format, ...) を使う場合。 */
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Hello, world!\n");
return 0;
}
上記サンプルソース中の﹁
\n
﹂は、エスケープ文字\
によるエスケープシーケンスのひとつであり、改行︵ラインフィード︶を表す。
main
関数は標準的なプログラムエントリーポイントであり、プログラムを開始すると、ランタイムライブラリによるスタートアップ処理が実行された後にこのmain
関数が呼ばれる。引数のないバージョンと、コマンドライン引数をポインタ配列として受け取るバージョンどちらを使ってもよい[8]。
なお、printf
関数は書式文字列とそれに対応する可変個引数を受け取り、書式化された文字列として表示できる高機能な標準出力関数であるが、序盤から例示に使用している入門書もある。
main
関数とprintf
関数は、いずれも入門者や初学者にとっては最初の関門となる難解な関数であり、C言語によるプログラミングのハードルを高くしている一因でもある[9][10]。JavaやC#のような後発言語では、文字列の扱いや、可変個引数の扱いがより簡潔で安全になっている。Pythonのようなインタプリタや対話環境上で動作することを前提とした言語では、main
関数を定義する必要はない。
主な制御構造
編集主な標準ライブラリ関数
編集詳細は「標準Cライブラリ」を参照
歴史
編集誕生
編集
C言語は、AT&Tベル研究所のケン・トンプソンが開発したB言語の改良として誕生した︵#外部リンクの﹁The Development of the C Language﹂参照︶。
1972年、トンプソンとUNIXの開発を行っていたデニス・リッチーはB言語を改良し、実行可能な機械語を直接生成するC言語のコンパイラを開発した[11]。後に、UNIXは大部分をC言語によって書き換えられ、C言語のコンパイラ自体も移植性の高い実装のPortable C Compilerに置き換わったこともあり、UNIX上のプログラムはその後にC言語を広く利用するようになった。
ちなみに、﹁UNIXを開発するためにC言語が作り出された﹂と言われることがあるが、﹁The Development of the C Language﹂によると、これは正しくなく、経緯は以下の通りである。C言語は、当初はあくまでもOS上で動くユーティリティを作成する目的で作り出されたものであり、OSのカーネルを記述するために使われるようになるのは後の展開である。
●UNIXの開発当初、Multicsプロジェクトが目指していた高級言語によるOSの開発という目標は見送られた。
●アセンブリ言語でUNIXが作成されると、OS上で動くユーティリティを作成するためのプログラミング言語が必要とされた。
●ケン・トンプソンは、当初Fortranコンパイラを作ろうとしたが、途中で放棄し、新しい言語であるB言語を作成した。
●B言語はインタプリタ言語であったため動作が遅く、B言語でユーティリティを作ることはあまりなかった。
開発者達は、コンパイラなどのユーティリティを﹁システムプログラム﹂と呼んでいたが、それらの作成に使われる﹁システムプログラミング言語﹂は、OSのカーネルを作成するための言語という意味ではない[12]。
●B言語の欠点を解消するため、1971年に改良作業を開始した。
●1972年にC言語のコンパイラができあがり、UNIXバージョン2において、いくつかのユーティリティを作成するために使用された。
UNIX環境とC言語
編集
アセンブラとの親和性が高いために、ハードウェアに密着したコーディングがやりやすかったこと、言語仕様が小さいためコンパイラの開発が楽だったこと、小さな資源で動く実行プログラムを作りやすかったこと、UNIX環境での実績があり、後述のK&Rといった解説文書が存在していたことなど、さまざまな要因からC言語は業務開発や情報処理研究での利用者を増やしていった。特にメーカー間でオペレーティングシステムやCPUなどのアーキテクチャが違うUNIX環境では再移植の必要性がしばしば生じて、プログラムをC言語で書いてソースレベル互換[13]を確保することが標準となった。
C言語誕生時の環境と他言語との比較
編集
C言語の開発当初に使われた入力端末はASR-37であったことが知られている[12]。
ASR-37は1967年制定の旧ASCII ISO R646-7bitにもとづいており、﹁
{
﹂および﹁}
﹂の入力を行うことができたが、当時は一般的に使われていた入力端末ではなかった。
当時PDP-11の入力端末として広く使われていたのはASR-33であるが、これは1963年制定の旧ASCIIであるASA X3.4に準拠しており、﹁{
﹂や﹁}
﹂の入力を行うことはできなかった[14]。
このことは、ブロック構造に﹁{
﹂や﹁}
﹂を用いるC言語︵さらに元をたどればB言語︶は、当時の一般的な環境では使用不可能であったことを示している。
これは、C言語はその誕生当初にあっては一般に広く使われることを想定しておらず、ベル研究所内部で使われることを一義的に考えた言語であったという側面の表れである。
これに対し、PascalやBASIC等の当初から広く使われることを想定した言語では、ブロック構造に記号を用いずにbegin
とen
d
をトークンとして用いることや、コメント行を表す際に開始トークンとしてREM
という文字列を用いることなど、記号入力に制約がある多くの入力端末に対応できるように配慮されていた。この頃の他の言語やOSで大文字と小文字の区別をしないものが多いのも、当時は大文字しか入力できない環境も少なくなかったことの表れである。
このような事情のため、C言語が普及するのは、ASCII対応端末が一般化した1980年代に入ってからである。
現在、ブロック構造の書式等で、{...}
形式のC言語と、begi
n...end
等を使用する他の言語との比較において優劣を論じられることがあるが、開発時の環境等をふまえずに現時点での利便性のみで論じるのは適切ではない場合があることに留意が必要である。
PCとC言語
編集
1980年代に普及し始めたパーソナルコンピュータ (PC) は当初、8ビットCPUでROM-BASICを搭載していたものも多く、BASICが普及していたが、1980年代後半以降、16ビットCPUを採用しメモリも増えた︵ROM-BASIC非搭載の︶PCが主流になりだすと、Turbo CやQuick Cといった2万円程度の比較的安価なコンパイラが存在したこともあり、ユーザーが急増した。8ビットや8086系のPCへの移植は、ポインタなどに制限や拡張を加えることで解決していた。
現在のC言語
編集
1990年代中盤には、最初に学ぶプログラミング言語としても主流となった。また、同時期にはゲーム専用機︵ゲームコンソール︶の性能向上とプログラムの大規模化、マルチプラットフォーム展開を受け、メインの開発言語がアセンブラからC言語に移行した。
1990年代後半から2000年代以降は、PCのさらなる性能向上と普及、GUI環境やオブジェクト指向の普及、インターネットおよびウェブブラウザの普及、スマートフォンの普及に伴い、より高水準で開発効率の高い言語やフレームワークを求める開発者が増えたことにより、C++、Visual Basic、Java、C#、Objective-C、PHP、JavaScriptなどが台頭してきた。広く利用されるプログラミング言語の数は増加傾向にあり、相対的にC言語が使われる場面は減りつつある。特にアプリケーションソフトウェアなどの上位層の開発には、C言語よりも記述性に優れるC++、Java、C#などC言語派生の後発言語が利用されることが多くなっている。資源制約の厳しかったゲーム開発においても、ハードウェアの性能向上やミドルウェアの普及により、C++やC#などが使われる場面が増えている。速度性能や省メモリが特に重視されるシステムプログラミングに関しても、伝統的にC/C++の独壇場だったが、新規コードではより安全性の高いRustを導入する事例が現れている[15][16]。
しかし、C言語は比較的移植性に優れた言語であり、個人開発/業務用開発/学術研究開発やプロプライエタリ/オープンソースを問わず、オペレーティングシステムやデバイスドライバーなどの下位層、クロスプラットフォームAPIの外部仕様、C++やJavaなどの高水準言語の処理系および実行環境の実装が困難な小規模の組み込みシステムなどを中心に、2021年現在でも幅広く利用されている。
プログラミング入門者にとっては、Python、JavaScript、Swift、Kotlinなどのように、インタラクティブな対話環境︵REPL、インタプリタ︶が利用でき、抽象化が進んでおり、煩雑なメモリ管理が不要で、危険な機能を制限した高水準言語のほうが学習・習得しやすいが、コンピュータの動作原理やハードウェア仕様を理解するには、Cのような原始的な言語を用いたほうがかえって分かりやすいケースもある。
規格
編集K&R
編集「プログラミング言語C」も参照
米国国家規格協会(ANSI)による標準化が行われるまで、1978年出版のデニス・リッチーとブライアン・カーニハンの共著『The C Programming Language』が実質的なC言語の標準として参照されてきた。この書籍は、著者らのイニシャルを取って「K&R」とも呼ばれている。C言語は発展可能な言語で、K&Rの記述も発展の可能性のある部分は厳密な記述をしておらず、曖昧な部分が存在していた。そのためC言語が普及するとともに、互換性のない処理系が数多く誕生した。
C89/C90
編集詳細は「ANSI C」を参照
そこで、ISO/IEC JTC1とANSIは協同でC言語の規格の標準化を進め、1989年12月にANSIがANSI X3.159-1989, American National Standard for Information Systems -Programming Language-Cを、1990年12月にISOがINTERNATIONAL STANDARD ISO/IEC 9899 : 1990(E) Programming Languages-Cを発行した。ISO/IEC規格のほうが章立てを追加しており、その後ANSIもISO/IEC規格にならって章立てを追加した。それぞれC89 (ANSI C89) およびISO/IEC C90という通称で呼ぶことがある。
日本では、これを翻訳したものを﹃JIS X 3010-1993 プログラム言語C﹄として、1993年10月に制定した。
最大の特徴は、C++と同様の関数プロトタイプ[注釈4]を導入して引数の型チェックを強化したことと、
void
やenum
などの新しい型を導入したことである。一方、﹁処理系に依存するものとする﹂に留めた部分も幾つかある︵int
型のビット幅、char
型の符号、ビットフィールドのエンディアン、シフト演算の挙動、構造体などへのパディング等︶。
規格では以下の3種類の自由を認めている部分がいくつかある[17]。
●規格で定義しないことを決めている﹁未定義﹂ (undefined)
●規格で選択肢を定義したもののどれにするかを決めておらず、処理系が選択する必要があるが、文書化の必要はない﹁未規定﹂ (unspecified)
●処理系ごとに決めて文書化する必要のある﹁処理系定義﹂ (implementation-defined)
これにより、プラットフォームやプロセッサアーキテクチャとの相性による有利不利が生じないような仕様になっている。
8ビット/16ビット/32ビットなど、レジスタ幅︵ワードサイズ︶の異なるプロセッサ (CPU) に対応・最適化できるようにするため、組み込み型の情報量︵大きさ︶や内部表現にも処理系の自由を認めている。型のバイト数はsizeof
演算子で取得し、各型の最小値・最大値はlimits.h
で定義されているマクロ定数で参照することとしている。ただし、1バイトあたりのビット数は規定されていない。si
zeof(char) == 1
すなわちchar
型が1バイトであることは常に保証されるが、8ビット︵オクテット︶とは限らない。実際のビット数はCHAR_BIT
マクロ定数で取得できる。とはいえ、現実の多くの処理系ではchar
型は8ビットである。また、その他の整数型については、sizeof(int) >= 2
、sizeof(
int) >= sizeof(short)
、sizeof(lon
g) >= sizeof(int)
、という大小関係が定められているだけである︵符号無し型も同様︶。多くの処理系ではshort
型のサイズは2バイト︵16ビット︶であるが、int
やlong
のサイズはCPUのレジスタ幅などによって決められることが多い。int
型、s
hort
型、long
型で符号を明示しない場合はsigned
を付けた符号付き型として扱われる。しかしchar
型に関しては、sign
ed
︵符号付き︶にするか、それともunsigned
︵符号無し︶にするかは処理系依存である。char
型、signed char
型、unsigned char
型はそれぞれ異なる型として扱われる。
規格上には、BCPLやC++形式の1行コメント︵
//…
︶は無いが、オプションで対応した処理系も多く、gccやClangはGNU拡張-std=gnu89
でサポートしている。
GNU Cコンパイラ や Clang では、-std=c89
︵または-ansi
もしくは-std=c90
︶をつけることにより、GNU拡張を使わないC89規格に準拠したコンパイルを行うことができる[注釈5]。加えて、-pedantic
をつければ診断結果が出る。商用のコンパイラではWatcom Cコンパイラが規格適合の比率が高いと言われていた。現在Open Watcomとして公開している。
C89には、下記の追加の訂正と追加を行った。
- ISO/IEC 9899/COR1:1994
- ISO/IEC 9899/AMD1:1995 - 英語圏での利用を想定して制定したC89に対して、国際化のためワイド文字版ライブラリを追加したAmendment1が1995年に発行された。
- ISO/IEC 9899/COR2:1996
C99
編集詳細は「C99」を参照
1999年12月1日に、ISO/IEC JTC1 SC22 WG14 で規格の改訂を行い、C++の機能のいくつかを取り込むことを含め機能を拡張し、ISO/IEC 9899:1999(E) Programming Language--C (Second Edition) を制定した。この版のC言語の規格を、通称としてC99と呼ぶ。
日本では、日本産業規格 JIS X 3010:2003﹁プログラム言語C﹂がある。
主な追加機能‥
●変数宣言がブロックの先頭でなくても良くなった。
●ブール代数を扱うための
_Bool
型が予約語に追加され、標準ライブラリとしてstdbool.h
を追加した。
●複素数を扱うための_Complex
型や_Imaginary
型を予約語に追加し、標準ライブラリとして、complex.h
を追加した。
●少なくとも64ビットの整数値を保持できる long long i
nt
型の追加。
●オプションとして、固定幅かつ内部表現の規定された整数型の標準化︵stdint.h
︶。
●//
による1行コメント。
●インライン関数︵inline
キーワード︶。
●可変長配列︵alloca
関数の代替︶[18]。
C99は下記の訂正がある。
- ISO/IEC 9899:1999 Cor. 1:2001(E)
- ISO/IEC 9899:1999 Cor. 2:2004(E)
- ISO/IEC 9899:1999 Cor. 3:2007(E)
C11
編集詳細は「C11 (C言語)」を参照
2011年12月8日にISO/IEC 9899:2011︵通称 C11︶として改訂された。
C11はUnicode文字列︵UTF-32、UTF-16、UTF-8の各符号化方式︶に標準で対応している。そのほか、
type-g
eneric
式、C++と同様の無名構造体・無名共用体、排他的アクセスによるファイルオープン方法、quick_exitなどのいくつかの標準関数などを追加した。
また、_Noreturn
関数指示子を追加した。_Noreturn
は従来処理系ごとに独自に付加していた属性情報︵たとえばgccでは__attribute__((__noreturn__))
︶を標準化したもので、﹁呼び出し元に戻ることがない﹂という特殊な関数についてその特性を示すためにある。return
文を持たない関数という意味ではなく︵規格ではreturn
文を持たなくとも、関数の最後の文の実行が終われば制御は呼び出し元に戻る︶、_exit
やexe
cve
を実行したり、例外、longjmp
による大域ジャンプ[注釈6]などのために、制御が呼び出し元に戻らないことを明示するためにある。そのような関数は、スタックに戻りアドレスを積む通常の呼び出しではなく、スタックを消費しないジャンプによって実行できる。
C11規格では一部の機能を省略可能とした。すなわちコンパイラがC11に合致していても、一部機能は提供しないことがある。コンパイラがどの機能を提供しているかは、テスト用のマクロで判別できる。アラインメント機能や_Atomic
型、C言語ネイティブの原始的なスレッド機能などが、C11では省略可能な機能として追加された。また、複素数型と可変長配列はC99では必須機能であったが、C11では省略可能である。
gets
関数が廃止された。
C17
編集2018年にISO/IEC 9899:2018(通称C17またはC18)として改訂された。仕様の欠陥修正がメインのマイナーアップデートである[19]。
主なC言語処理系
編集大抵の処理系はC言語とC++両方をサポートしている。C言語とC++の共通部分を明確にし、二つの言語の違いに矛盾が生じないようにすることが課題になっている。
Linux、Windows、UNIX用
編集
C++ Builder
Windows/macOS/iOS/Android対応のC/C++コンパイラBCCを含む、RADツール。以前はWindowsおよびx86のみがメインターゲットだったが、Clang/LLVMをベースに再設計され、多数のプラットフォームやアーキテクチャをサポートするようになった[20]。前身はDOS/Windows用のBorland C/C++。さらに前身としてTurbo C/C++がある。
Clang
LLVMをバックエンドとして用いるオープンソースのC/C++・Objective-Cコンパイラ。多数のCPUに対応。
GNUコンパイラコレクション (GCC)
C/C++以外の言語もサポートし、多数のCPUやオペレーティングシステムに対応、組み込み向けも含む多様な開発に広く使われるオープンソースのコンパイラ。独自拡張機能も多い。
GCC 4.5で実質的にC99を完全サポートした[21]。
GCC 4.9で実質的にC11を完全サポートした[22]。
Microsoft Visual C++ (MSVC)
Windows系プラットフォーム用のC/C++コンパイラ。ANSI C準拠︵バージョン2013にてC99ライブラリをほぼ実装したが、言語機能など規格自体はサポートされていない︶。x86・x64が主だが、Xbox 360、Windows CE等向けにPowerPC、ARM、MIPS、Itanium等に対応した版もある。前身としてMS-DOS・Windows用のMicrosoft C Compilerがある。またその廉価版としてQuick Cがあった[23]。
Intel C++ Compiler (ICL/ICC)
インテル製のIA-32 (x86) およびIntel 64 (x64) 用のC/C++コンパイラ。Windows/Linux/macOS/Android向けがある。gcc互換。
バージョン11.1まではIA-64 (Itanium) をサポートするが、バージョン12.0以降ではサポートされない[24]。
C99[25]とC11[26]の対応リストが公開されている。バージョン18.0でC11にほぼ対応している。
Open Watcom C/C++
Windows・Linux・OS/2・MS-DOS・DOSエクステンダを対象とするx86用C言語・C++コンパイラ。商用だったWatcom C/C++がオープンソース化したもの。
Portable C Compiler
gccが普及する以前のUNIXにおける標準的C言語コンパイラ。現在はオープンソース。
Digital Mars C/C++
Windows・MS-DOS・DOSエクステンダを対象とするx86用のC言語・C++コンパイラ。無料版もある。ウォルター・ブライト作でDatalight C、Zorland C、Zortech C/C++、Symantec C/C++と変遷している。
組み込み用、8ビット・16ビット・32ビット・64ビットCPU用(クロスコンパイラ)
編集
Green Hills Software C/C++
組み込み向けのC言語・C++コンパイラ。 Windows用・Solaris用・Linux用があり、HP/UX用がver4ではあった。
CodeWarrior C/C++
組み込み向けやゲーム機開発向けのC言語・C++コンパイラ。Classic Mac OS用として発祥、かってはWindows用・BeOS用・Palm用もあった。
ARM C/C++
ARM CPU用C言語・C++コンパイラ。
IAR C/C++
新旧の組み込み向けCPU各種を広くカバーする。現在は統合開発環境EW・SWに移行。ARM CPU用C言語・C++コンパイラが著名。ARMをコアにした各社のCPUに対応している。
High C
元はx86向けでPC/AT互換機用だが80386のネイティブモードに対応したためFM TOWNSでも標準開発環境、﹁High C 386﹂として使用された。現在は各社RISC向け。
BDS-C
CP/M︵8080・Z80︶用のサブセット︵整数のみ︶のK&R系のC言語コンパイラ。現在はパブリックドメインソフトウェア。
Hitech-C
Z80、PICなど。
Lattice C
1980年代に、日本で高い普及率を見せたコンパイラ。解説書も多く出版されていた。日本での発売はライフボート。初期版はマイクロソフトCコンパイラ1.0として発売された。商用利用のできない個人向けの﹁personal﹂版も販売されており、これの価格は19,800円であった[27][28]
LSI C
8080・Z80用のLSI C-80︵セルフ版・クロス版。現在はクロス版のみ︶と、8086用のLSI C-86がある。8086では機能限定︵スモールモデルのプログラムしか開発できず、デバッガがない︶の﹁試食版﹂がフリーソフトで公開され、広く使われた。
micro-C
8ビット・マイクロプロセッサMC6809用C言語サブセット・コンパイラ[29]。
関連する主なプログラミング言語
編集先祖
編集
ALGOL
ヨーロッパ生まれのアルゴリズム記述言語。PascalやC言語などに影響を与えたとされる。
BCPL
MULTICSで作成された高級言語。
B言語
初期のUNIXで作成されたインタプリタ方式の高級言語。BCPLを元に作られ、Cの原型となった。
継承・拡張・サブセット
編集
C++
C言語を拡張してオブジェクト指向化したもの。Simulaの影響を強く受けている。当初はC言語のスーパーセットだったが、現在は細かい部分において非互換仕様が増えている。
Objective-C
C言語を拡張してオブジェクト指向化したもの。C言語に Smalltalk のオブジェクトシステムを取り付けたような設計で、互換性は保たれている。C言語からの拡張部分がC++と干渉しないため、C++と混在した記述が可能。
Java
C++よりも言語文法レベルでオブジェクト指向を重視した言語。バッファオーバーランなどの危険性が高いポインタといったローレベルな要素を言語文法から排除している。仮想マシン︵Java VM, JVM︶上で動作する。
C#
マイクロソフトが.NET Framework向けに開発した言語。文法はC言語およびC++に近い書式を持ち、Javaと似ている部分も存在するが、機能的にはDelphiがベースとなっている。
Rust
C言語およびC++に代わるシステムプログラミング言語を目指している言語。言語レベルでのRAIIの強制による自動メモリ管理機構を持ち、ガベージコレクション無しでも手動のメモリ管理が不要であり、実行性能はC/C++と同等である。
Cyclone
C言語の上位互換セキュア実装。ポインタの扱いを厳格化して安全面に配慮して拡張したもの。その他リージョンベースメモリ管理システム、正規表現、タグ付共用体などを追加している。
SystemC
ハードウェア記述言語向けに拡張したもの。書式はC++。IEEE 1666-2005。ISO 8866:1991。
Impulse C
ハードウェア記述言語向けに拡張したもの。書式はC。
Unified Parallel C
並列計算向けにC99を拡張して作られた言語。
Cg
C言語をGPU上での3次元コンピュータグラフィックス処理用に特化させたもの︵シェーダー言語、シェーディング言語︶。NVIDIAによって開発された。
注釈・出典
編集注釈
編集
(一)^ 英語ではC-family, C-style, C-likeなどと呼ばれる。﹁C系﹂の定義は明確ではないが、構文がCに類似しているものを指すことが多い。
(二)^ 例えばポインタのエイリアシングは最適化やベクトル化を妨げる[1]。
(三)^ 他の言語、例えば、BASICやPascalではプログラム開始直後に実行するプログラム要素はサブルーチンや手続きや関数ではない。
(四)^ C89においては関数プロトタイプは必須ではない。
(五)^ C89規格に準拠しないソースコードをGNU Cコンパイラでコンパイル失敗させるには、
gcc -ansi -pedantic -fstrict-aliasing -Wall -Wextra -Wmissing-declarations -Werror test.cとすれば良い︵→エイリアシング︶。 (六)^
setjmp.h
を参照。
出典
編集
(一)^ ポインター・エイリアシングとベクトル化 | iSUS
(二)^ もう一度基礎からC言語 第19回 いろいろな演算子~ビット演算子Cは高級アセンブラ?
(三)^ 第1回 Chapter 1 C言語の概要︵1︶‥Cプログラミング入門|gihyo.jp … 技術評論社
(四)^ ISO/IEC 14882:2003 §3.6.1 ﹁The function main shall not be used within a program.﹂
(五)^ JIS X 3014:2003﹁プログラム言語C++﹂︵日本産業標準調査会、経済産業省︶ §3.6.1 ﹁関数mainは、プログラムの中で挙用してはならない。﹂
(六)^ EXP33-C. 未初期化のメモリを参照しない JPCERT/CC、2014年3月25日︵2014年8月22日閲覧︶。
(七)^
“Memory Allocation Guide”. The Linux Kernel documentation. 2023年11月8日閲覧。
(八)^ main 関数 - cppreference.com
(九)^ ﹇Python入門﹈Pythonってどんな言語なの?‥Python入門︵1/2 ページ︶ - @IT
(十)^ Hello, Worldプログラム | Programming Place Plus C言語編 第2章
(11)^ Portability of C Programs and the UNIX Systems
(12)^ abThe Evolution of the Unix Time-sharing System
(13)^ ソースレベル互換 - ZDNet Japan
(14)^ http://www.tohoho-web.com/ex/draft/kanji.htm
(15)^ Rust言語でAndroidはより強固・安全に ~GoogleがOS開発への導入を進める - 窓の杜
(16)^ Microsoft、Windows 10の一部をRustへ書き換えてセキュリティ強化狙う | TECH+
(17)^ C FAQ 11
(18)^ 6.19 Arrays of Variable Length
(19)^ Cの歴史 - cppreference.com
(20)^ Clang 拡張 C++ コンパイラ - RAD Studio
(21)^ Status of C99 features in GCC - GNU Project - Free Software Foundation (FSF)
(22)^ C11Status - GCC Wiki
(23)^ “Microsoft Releases C Program Wares, Provides Rebates”. InfoWorld: p. 29. (1987年11月9日)
(24)^ インテル® C++ Composer XE 2011 Windows* 版インストール・ガイドおよびリリースノート - w_ccompxe_2011.7.258_Release_Notes_ja_JP.pdf
(25)^ C99 Support in Intel® C++ Compiler | Intel® Software
(26)^ C11 Support in Intel C++ Compiler | Intel® Software
(27)^ 脇英世︵監修︶、1987、﹃パソコンの常識事典﹄、日本実業出版社 pp. 339、342 - 普及率、解説書の多さについて。
(28)^ 長沢英夫︵編︶、1988、﹃パソコンベストソフトカタログ﹄、JICC出版局 pp. 201 - Personal版、解説書の多さについて。
(29)^ ucom10 1983, p. 80.
参考文献
編集
2015年現在、初心者向けのイラスト入り入門書やサブルーチンのサンプル集の他、組み込み機器の制御や科学技術計算など目的を特化した専門書なども多数ある。便利な機能の説明はあっても、学習者の水準や目的にあった本を見つけるのは必ずしも容易でない。オープンソースのCコンパイラ、OSも大規模なものがあり、直接読み始めるのは困難になっている。オープンソースのOSの小規模なものから始めるとよい。
プログラミング言語C
ブライアン・カーニハン、デニス・リッチー 共著、石田晴久訳、共立出版。
﹁K&R﹂として知られている﹁The C Programming Language﹂の邦訳。入門書ではなく、特にプログラミングそのものが初めてという読者には不適である。初版と第2版があり、第2版が現在も時折増刷されている︵邦訳では事情により、原書第2版を基とした版には旧版と改訂新版がある。旧版は装丁が緑地で新版は白地である︶。標準の制定以前は本書初版を言語仕様の参考文献として扱っていたが、現在はISOなどの標準規格を参照すべきであり、本書の記述は参考にとどめるべきである。なお、日本工業規格︵現・日本産業規格︶のJIS X 3010:2003﹁プログラム言語C﹂は、ISO/IEC JTC1 SC22 WG14+ISO/IEC 9899:1999 Cor. 1:2001(E)つまりC99の和訳相当で、2021年8月現在の最新規格であるISO/IEC 9899:2018との乖離を生じている。
Cプログラミングの落とし穴
コーニグ、中村明訳、新紀元社
Cプログラミングで嵌まるところを指摘している。MISRA Cでも参考文献になっている。
Cパズルブック
アラン・R. フューアー、田中和明訳、カットシステム
Cプログラミングの芸当を示し、読み書きを推奨しない例を示している。
﹃マイコンピュータ No.10﹄CQ出版社、1983年9月1日。
入門特集C言語の研究
外部リンク
編集- ISO C Working Group
- The Development of the C Language - C言語がどのように開発されたかがわかる文書
- stdio.h on Coding Programmer Page / C Library Reference and Examples - C Reference
- C言語リファレンス - cppreference.com - 標準C/C++のオンライン言語リファレンス