C言語
テンプレート:Infobox プログラミング言語 テンプレート:プログラミング言語 テンプレート:Sister C言語(シーげんご)は、1972年にAT&Tベル研究所のデニス・リッチーが主体となって作ったプログラミング言語である。英語圏では単に C と呼称されており、日本でも文書や文脈によっては同様に C と呼称される。
UNIX の移植性を高めるために開発された経緯から、オペレーティングシステムカーネル向けの低レベルな記述ができることを特徴としている。
特徴
C 言語は手続き型言語であり、コンパイラ言語として設計された。C 言語は、自由度、実行速度、コンパイル速度などを追求したが、代わりにコンパイル後のコードの安全性を犠牲にもしているので、コンピュータ寄りの言語仕様になっている。
- アマチュアからプロのエンジニアまで、非常にプログラマ人口が多い。C 言語は正負の両面含めてコンピュータの世界に大きな影響を及ぼしているが、最大の原因はそのプログラマ人口の多さであると言われている。
- パソコンはもちろんのこと、組込み用マイコンから大型コンピュータまで、C 言語を使用できるプラットホームは多様である。また、仕様規格・派生言語も多い。
- 採用されているソフトウェア分野が広い。あらゆる分野に対してある程度の言語適性があり、現実的な選択肢としてよく用いられる。発祥元である UNIX の場合、大抵のことがスクリプト言語・マクロプロセッサやフィルタやそれらの組み合わせで処理できるため、うまく分野の棲み分けができていた面があったのだが、幅広い領域に移植された結果、適切でない分野に C 言語が使われている場面もある。
- 低水準な記述が出来る高級言語とも、高級言語の顔をした低級言語とも言われる。また、コーディング上の自由度が非常に高い。そのため良くも悪くも何でも出来てしまう強力さは多くのプログラマの支持を集める一方で、セキュリティー脆弱性や潜んだバグによる想定外の動作、コンパイラによる最適化の難しさがあり、それゆえにコンパイル速度が遅いなどの欠点の原因ともなっている。
- 商用・非商用を問わずコンパイラや C 言語向けのエディタが豊富で開発環境が整備しやすい。
C 言語の主な特徴は以下の通りである(歴史的な経緯から BASIC や Pascal と比較されることが多い)。
自由度
- 文の区切りを区切り記号 セミコロン「
;
」で表し、改行文字にも空白にもトークンの区切りとしての意味しか持たせない「フリーフォーマット」という形式を採用している。- 記述作法について、しばしば議論の対象となり、本も多数出版されている。
- ALGOL の思想を受け継いで構造化をサポートしており、手順を入れ子構造で示して見通しの良い記述をすることができる。原理的に無条件分岐(
goto
)を使用する必要が軽減されるため、スパゲティプログラムと呼ばれるような読みにくいプログラムになりにくい。 - モジュール化がファイルを単位として可能。モジュール内だけで有効な名前を使うことが出来るスコープを持っている。
- プログラムを関数(戻り値つきのサブルーチン)に分離できる。関数の中では独立した変数が使用でき、データの流れがブロックごとに完結しデバッグが容易になる。また、多人数での共同開発の際にも変数名の衝突が回避できる。なお C 言語ではUNIXのようなOSを前提としたホスト環境と、UNIXのようなOSを前提としないフリースタンディング環境とがある。ホスト環境では、プログラム開始直後に実行するプログラム要素を
main
という名前の関数として定義する[1]。プログラム中で再帰的にmain
関数を呼ぶことも可能。(C++ では不可能[2][3])フリースタンディング環境では、mainという名前でなくてもよく、引数をどのようにするかを決めることができる。 - C言語では、main関数とprintf, scanfの3つのグループの関数が引数が可変という特殊な性格の関数である。K&Rでは、この特殊な関数mainとprintfを使った例を最初に示している。C言語理解を困難にする理由の一つに、例外的な関数から教えていることによる。
- オペレーティングシステムを記述する言語として設計されたため、高級言語であるがアセンブラ的な低レベルの操作ができる。ポインタ演算、ビットごとの論理演算、シフト演算などの機能を持ち、ハードウェアに密着した処理を効率よく記述できる。これはオペレーティングシステムやドライバなどを記述する上では便利であるが、注意深く利用しないと発見しにくいバグの原因となる。
- 配列とポインタとでは、宣言の仕方と領域確保の仕組みは異なっているが、配列アクセスそのものは、ポインタ演算および間接参照と同等である。
- ポインタを配列表記でアクセスすることや、配列をポインタ表記でアクセスすることができる糖衣構文がある。
- ソースコードの記述に使われる文字セットは ASCII を標準としているが、他のISO 646でも書けるように、トライグラフと呼ばれる表記法も存在する。
アセンブラとのインターフェース
- 多くの処理系がインラインアセンブラを搭載しているほか、アセンブラで出力したオブジェクトとのリンクが容易になっている。これにより速度が要求される部分だけをアセンブリ言語で記述するということが容易に行えることが多い。もっとも、アセンブラとのインターフェースに統一された仕様はなく CPU が同一であっても移植性は低い。
コンパイラ仕様
- コンパイラの処理が1パスで済む仕様になっている。具体的には、変数はその使用より前に宣言をする必要があり、関数は宣言がないとint型が適用されるなど。(後継言語では記述によって先読みが必要になりうる)
- 標準でマクロ記述やコンパイル条件の指定が出来るプリプロセッサを持ち、その名の通りコンパイル処理の前に実行される。
処理系の簡素化
- 配列参照時の自動的な添字のチェックをしない
- これを要因とする代表的なバグがバッファオーバーフロー(固定長のバッファをはみだして上書きが行われてしまう)である。標準ライブラリにはバッファオーバーフローを考慮していない関数があり、かつ多用されがちなため、しばしば脆弱性の原因となる。また、プログラムにより制御する事で可変長配列を可能にしている。
- 文字列を格納するための特別な型が存在しない
- 文字列にはchar型の配列やポインタを利用する。言語仕様上に特別な扱いはないが、ヌル文字(
\0
)を終端とする文字列表現を使い、その操作をする標準ライブラリ関数が提供されている。これは実質的にメモリ領域のポインタアクセスそのもので、バッファオーバーランの元凶の1つとなっている。後継言語では文字列処理が特に強化されている場合が多い。 - 自動変数の自動的な初期化をしない
- 自動変数(静的でないローカル変数)は変数の中でも最も頻繁に用いられる。初期化しない変数を参照した場合、値は不定となるが、不定な値へのアクセスはテンプレート:仮リンクであるので、コンパイラ最適化の過程で想定しない形に改変されることもある[4]。変数宣言・初期化の仕様による制限から、変数宣言の時点で初期化せず後で代入することで初期化に代えることが日常的で、誤って不定の値の変数を読み出すバグを作り込みやすい。なお自動変数の自動とは変数の領域の確保と開放が自動であるという意味であり、自動的に初期化されるという意味ではない。
その他
- 文字の大文字・小文字が区別される。
- 入出力を含め、ほとんどの機能を C 言語自身で書かれたライブラリが提供する。このことは、C 言語が機種依存性が低く、入出力関係ライブラリをのぞいた部分は移植性(ポータビリティ)が高いことを意味するテンプレート:要出典。さまざまな機種がある UNIX の世界で C 言語が普及した理由のひとつである。
- プログラムの実行に必要とするハードウェア資源が、(アセンブラよりは多いが)他の高級言語より少なくてすむため、現在さまざまな電化製品などの組み込みシステムにも使用されている。
- 組込み向けの場合は、プログラミング言語として、アセンブラ以外では、C 言語、C++ 言語しか用意されていないことも多い。
コード例
Hello world プログラム
C 言語の Hello world プログラムには、入門書によって趣が異なるいくらかのバリエーションが存在する。C 言語の標準ライブラリのprintf
関数を利用したものが最も一般的で、以下のようなものである。
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}
ここでサンプルソース中の「\n
」は改行を表す。なお、printf
関数は変数や書式化された文字列などが表示できる比較的高機能な出力関数である。
主な制御構造
主な標準ライブラリ関数
歴史
誕生
C 言語は、AT&T ベル研究所のケン・トンプソンが開発したB言語を改良して作られた(#外部リンクの「The Development of the C Language」参照)。
1973年、トンプソンとUNIXの開発を行っていたデニス・リッチーは B 言語を改良し、実行可能な機械語を直接生成する C 言語のコンパイラを開発した。UNIX は大部分が C 言語によって書換えられ、C 言語のコンパイラ自体も移植性の高い実装の Portable C Compiler に置き換わったこともあり、その後に C 言語は広く利用されるようになった。
UNIX 環境と C 言語
アセンブラとの親和性が高いためにハードウェアに密着したコーディングがやりやすかったこと、言語仕様が小さいためコンパイラの開発が楽だったこと、小さな資源で動く実行プログラムを作りやすかったこと、UNIX環境での実績があり、後述の K&R といった解説文書が存在していたことなど、さまざまな要因から C 言語は業務開発や情報処理研究での利用者を増やしていった。特にメーカー間でオペレーティングシステムやCPUなどのアーキテクチャが違う UNIX 環境では再移植の必要性がしばしば生じて、プログラムを C 言語で書いてソースレベル互換[5]を確保することが標準となった。
パソコンと C 言語
1980年代に普及し始めたパーソナルコンピュータでは当初 8 ビット CPU で ROM-BASIC を搭載していたものも多く BASIC が普及していたが、80年代後半以降 16ビット CPU を採用しメモリも増えた(ROM-BASIC 非搭載の)パソコンが主流になりだすと2万円前後の安価なコンパイラが存在したこともあり、ユーザーが急増した。8 ビットや 8086 系のパソコンへの移植は、ポインタなどに制限や拡張を加えることで解決していた。
現在の C 言語
1990年代中盤以降は、最初に学ぶプログラミング言語としても主流となった。GUI環境の普及とオブジェクト指向の普及により Java、Objective-C、C++、PHP、Visual Basic、などの言語の利用者も増加したため、広く利用されるプログラミング言語の数は増える傾向にあるが、現在でも C 言語は比較的移植性に優れた言語であり、業務用開発やフリーソフトウェア開発、C++ などの実装が困難な組み込みなどの小規模のシステムで、幅広く利用されている。
C 言語の規格
K&R
テンプレート:See also 1978年に出版された、リッチーとカーニハンの共著である「The C Programming Language」[6]は、その後標準化がなされるまで実質的な C 言語の標準として使用された。しかし、この本の記述にはいくつか曖昧な部分が存在していた。そのため、C 言語が普及するに従い、互換性のない処理系が数多く誕生することとなった。
C89
そこで、ISOと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 規格のほうが章立てが追加されており、その後 ANSI も ISO 規格にならって章立てを追加した。それぞれ C89(ANSI C89)及び ISO C90 という通称で呼ばれることがある。
日本では、これを翻訳したものが日本工業規格『JIS X3010-1993 プログラム言語C』として、1993年10月に制定された。
最大の特徴は、C++ と同様の関数プロトタイプ[7]を導入して引数の型チェックを強化したことと、void
や enum
などの新しい型を導入したことである。一方、処理系に依存するとするに留めた部分も幾つかある(int
型のビット幅、char
型の符号、ビットフィールドのエンディアン、シフト演算の挙動、構造体などへのパディング、等)。
また、型の大きさは厳密に決められてはおらず、バイト数は sizeof
演算子で取得し、最大最小値は limits.h
で参照することとされている。もっとも、多くの処理系では char
型は 8 ビット、short
型は16ビットである。ただし、int
や long
は環境によってまちまちである。また API などの呼び出しには、ヘッダで BYTE
や WORD
などと typedef
で定義した型を使用して回避するのが一般的になっている。char
型以外で符号を明示しない場合は signed
(符号付き)になる。
規格上には、BCPL・C++タイプの一行コメント(「//…
」)は無いが、オプションでサポートした処理系も多く、gcc や Clang は GNU 拡張 -std=gnu89
でサポートしている。
GNU C コンパイラ や Clang では、-std=c89
(もしくは-ansi
)をつけることにより、GNU 拡張を使わない C89 規格に準拠したコンパイルを行うことができる[8]。加えて、-pedantic
をつければ診断結果が出る。
C89には、下記の追加の改訂が行われた。
- ISO/IEC 9899/COR1:1994
- ISO/IEC 9899/AMD1:1995 - 主として英語圏での利用を想定して制定されたC89に対して、主に国際化のためワイド文字版ライブラリを追加した Amendment1 が1995年に発行された。
- ISO/IEC 9899/COR2:1996
C99
テンプレート:Main 1999年12月1日には、ISO で規格の改定が行われ、C++ の機能のいくつかを取り込むことを含めた機能拡張がなされ ISO/IEC 9899:1999(E) Programming Language--C (Second Edition) が制定された。この版の C 言語の規格を、通称としてC99と呼ぶ。Intel C++ Compiler は C99 に完全準拠していると公称している。GNU C コンパイラ(gcc)は C99 にほとんど対応しているが一部未対応部分も残っている[9]。
日本では、日本工業規格 JIS X 3010:2003「プログラム言語C」がある。
主な追加機能:
- 変数宣言がブロックの先頭でなくても良くなった。
- ブール代数を扱うための
_Bool
型が予約語に追加され、標準ライブラリーとしてstdbool.h
が追加された。 - 複素数を扱うための
_Complex
型や_Imaginary
型が予約語に追加され、標準ライブラリーとしてcomplex.h
が追加された。 - 64 ビット整数値を保持できる
long long int
型の追加。 //
による1行コメント。- インライン関数(
inline
キーワード)。 - 可変長配列(
alloca
関数の代替)[10]。
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
テンプレート:Main 2011年12月8日に改定されたISO/IEC 9899:2011(通称C11)が現在の最新規格である。gcc や Clang などで部分的にサポートされている。改定によって変更・追加・削除された機能の一部を以下に記述する。
C11 は Unicode文字列(UTF-32、UTF-16、UTF-8 の各符号化方式)に標準で対応している。そのほか、type-generic
式、C++ と同様の無名構造体・無名共用体、排他的アクセスによるファイルオープン方法、quick_exitなどのいくつかの標準関数などが追加された。
また、_Noreturn
関数指示子が追加された。これは従来各処理系毎に独自に追加されていた(たとえば gcc では __attribute__((__noreturn__))
)ものを共通化したもので、「呼び出し元に戻ることがない」という特殊な関数についてその特性を示すためにある。テンプレート:要出典、通常は return
文を持たなくとも、関数の最後の文の実行が終われば制御は呼び出し元に戻る。この指示が意味するものは、当該の関数、ないしその内部から呼び出している関数の実行中に、必ず _exit
や execve
を実行したり、例外などで終了する、あるいは、longjmp
による大域ジャンプで抜け出す[11]、継続渡しスタイル変換されたコードである、などのために、絶対に制御が呼び出し元に戻らない、という関数を指示するためにある。そのような関数は、スタックに戻りアドレスを積む通常の呼び出しではなく、スタックを消費しないジャンプによって実行できる。
_Atomic
型や C 言語ネイティブの原始的なスレッド機能などが省略可能な機能として規格に組み込まれた。また、C99 では規格上必須要件とされていた機能のうち、複素数型と可変長配列が省略可能なものに変更された。これらの省略可能な機能は C11 規格合致の必須要件ではないので、仮に完全に規格合致の処理系であっても、サポートしていないかもしれない。C11 規格では、省略可能な機能のうちコンパイラがどれを提供しているかを判別するために利用できる、テスト用のマクロを用意している。
gets
関数は廃止された。
主な C 言語処理系
現在は C 言語と C++ で兼用となっている処理系が多い。
Linux、Windows、UNIX 用
- C++ Builder
- Windows 用の x86 用 C 言語・C++ のコンパイラ。RAD。前身は DOS、Windows 用の Borland C/C++。さらに前身として Turbo C/C++ がある。
- clang
- LLVM をバックエンドとして用いるオープンソースの C 言語・C++・Objective-C コンパイラ。多数の CPU に対応。
- Digital Mars C/C++
- Windows・MS-DOS・DOSエクステンダを対象とする x86 用の C 言語・C++ コンパイラ。無料版もある。ウォルター・ブライト作で Datalight C、Zorland C、Zortech C/C++、Symantec C/C++ と変遷している。
- GNUコンパイラコレクション (GCC)
- C・C++ 以外の言語もサポートし、多数の CPU やオペレーティングシステムに対応、組み込み向けも含む多様な開発に広く使われるオープンソースのコンパイラ。
- Intel C++ Compiler
- インテル製の x86・x64用の C 言語・C++コンパイラ。Windows・Linux・OS X向けがある。gcc 互換。
- Microsoft Visual C++
- Windows 系プラットフォーム用の C 言語・C++ コンパイラ。2013 から C99 におおむね対応。x86・x64 が主だが Xbox 360、Windows CE 等向けに PowerPC、ARM、MIPS、Itanium 等をサポートしたバージョンもある。前身として MS-DOS・Windows 用の Microsoft C Compiler がある。またその廉価版として Quick C があった[12]。
- Open Watcom C/C++
- Windows・Linux・OS/2・MS-DOS・DOSエクステンダを対象とする x86 用 C 言語・C++ コンパイラ。商用だった Watcom C/C++ がオープンソース化したもの。
- Portable C Compiler
- gcc が普及する以前の UNIX における標準的 C 言語コンパイラ。現在はオープンソース。
組み込み用、8ビット・16ビットCPU用
- BDS-C
- CP/M(8080・Z80)用のサブセット(整数のみ)の K&R 系の C 言語コンパイラ。現在はパブリックドメインソフトウェア。
- CodeWarrior C/C++
- 組み込み向けやゲーム機開発向けの C 言語・C++ コンパイラ。Mac OS 用として発祥、かっては Windows 用・BeOS 用・Palm 用もあった。
- High C
- 元は x86 向けでPC/AT互換機用だが 80386 のネイティブモードに対応したため FM TOWNS でも標準開発環境、「High C 386」として使用された。現在は各社RISC向け。
- Hitech-C
- Z80、PICなど。
- IAR-C/C++
- 新旧の組み込み向け CPU 各種を広くカバーする。現在は統合開発環境 EW・SW に移行。
- Lattice C
- 1980年代に、日本で高い普及率を見せたコンパイラ。解説書も多く出版されていた。日本での発売はライフボート。初期版はマイクロソフトCコンパイラ1.0として発売された。商用利用のできない個人向けの「personal」版も販売されており、これの価格は 19,800 円であった[13][14]
- LSI C
- 8080・Z80用の LSI C-80(セルフ版・クロス版。現在はクロス版のみ)と、8086 用の LSI C-86 がある。8086 では機能限定(スモールモデルのプログラムしか開発できず、デバッガがない)の「試食版」がフリーソフトで公開され、広く使われた。
関連するプログラミング言語
先祖
- ALGOL
- ヨーロッパ生まれのアルゴリズム記述言語。Pascal や C 言語などに影響を与えたとされる。
- BCPL
- MULTICS で作成された高級言語。
- B言語
- 初期の UNIX で作成されたインタプリタ方式の高級言語。BCPLを元に作られ、Cの原型となった。
拡張
- C++
- C 言語を拡張してオブジェクト指向化したもの。当初は C 言語のスーパーセットだったが、現在は細かい非互換部分が増えている。
- Cg
- C 言語を GPU でのグラフィック処理用に特化させたもの(シェーダー言語)。NVIDIA によって開発された。
- Cyclone
- C 言語の上位互換セキュア実装。ポインタの扱い厳格化して安全面に配慮して拡張したもの。その他リージョンベースメモリー管理システム、正規表現、タグ付共用体などを追加している。
- Objective-C
- C 言語を拡張してオブジェクト指向化したもの。C 言語に Smalltalk のオブジェクトシステムを取り付けたような設計で、互換性は保たれている。C 言語からの拡張部分が C++ と干渉しないため、C++ と混在した記述が可能。
- SystemC
- ハードウェア記述言語向けに拡張したもの。
- Unified Parallel C
- 並列計算向けに C99 を拡張して作られた言語。
その他にも、OpenGLシェーダー言語であるGLSL、DirectX(Direct3D)シェーダー言語であるHLSL、OpenCLカーネル記述言語であるOpenCL-Cなど、C言語の文法的特徴を取り入れた派生言語やDSLが多数存在する。
参考文献
2010年現在では、初心者向けのイラスト入り入門書やサブルーチンのサンプル集の他、組み込み機器の制御や科学技術計算など目的を特化した専門書なども多数発行されているので、学習者のレベルや目的にあった本を見つけるのが容易な言語の一つでもある。
- プログラミング言語C
- ブライアン・カーニハン、デニス・リッチー 共著、石田晴久訳、共立出版。
- 「K&R」として知られている「The C Programming Language」の邦訳。入門書ではなく、特にプログラミングそのものが初めてという読者には不適である。初版と2版があり、2版が現在も時折増刷されている(邦訳では事情により、原書2版を基とした版には旧版と改訂新版がある。旧版は装丁が緑地で新版は白地である)。標準の制定以前は本書初版が言語仕様のリファレンスとして扱われていたが、現在はリファレンスとしては規格票を参照すべきであり、本書の記述は参考にとどめるべきである。
脚注
外部リンク
- ISO C Working Group
- The Development of the C Language - C 言語がどのように開発されたかがわかる文書
- stdio.h on Coding Programmer Page / C Library Reference and Examples - C Reference
- ↑ 他の言語、例えば、BASIC や Pascal ではプログラム開始直後に実行するプログラム要素はサブルーチンや手続きや関数ではない。
- ↑ ISO/IEC 14882:2003 3.6.1 「The function main shall not be used within a program.」
- ↑ JIS X 3014:2003 3.6.1 「関数mainは、プログラムの中で挙用してはならない。」
- ↑ EXP33-C. 未初期化のメモリを参照しない JPCERT/CC、2014年3月25日(2014年8月22日閲覧)。
- ↑ http://japan.zdnet.com/glossary/exp/%E3%82%BD%E3%83%BC%E3%82%B9%E3%83%AC%E3%83%99%E3%83%AB%E4%BA%92%E6%8F%9B/?s=4
- ↑ 「K&R」という通称がある。
- ↑ C89においては関数プロトタイプは必須ではない。
- ↑ C89 規格に準拠しないソースコードをGNU C コンパイラでコンパイル失敗させるには、
gcc -ansi -pedantic -fstrict-aliasing -Wall -Wextra -Wmissing-declarations -Werror test.c
とすれば良い(→エイリアシング)。 - ↑ Status of C99 features in GCC
- ↑ 6.19 Arrays of Variable Length
- ↑
setjmp.h
を参照。 - ↑ テンプレート:Cite news
- ↑ テンプレート:Cite book ja-jp - 普及率、解説書の多さについて。
- ↑ テンプレート:Cite book ja-jp - Personal版、解説書の多さについて。