気の向くままに辿るIT/ICT/IoT
プログラミング言語

C / C言語 / C Language

ホーム前へ次へ
C言語とは?

C / C言語 / C Language

C / C言語 / C Language

 1969年アセンブリ言語で書かれ開発されたUNIXが1970年、71年に誕生しますが、その後他のハードウェアへの移植性を高める為、UNIX開発者自身が作った言語がB言語(←BCPL[Basic CPL/Bootstrap]←CPL[Cambridge Programming Language]←FORTRAN・ALGOL60・COBOLの各概念)、更にB言語に改良を加えたC言語で書き直され1972年にC言語ベースのUNIXが生まれたそうです。

 以後C言語は、UNIX、また1991年に開発されたUNIX互換のLinux、更にWindows上の開発言語としても現代に至るまで使い続けられている比較的人間に理解しやすいプログラミング言語で文法含め、後のscriptC++・C++/CLI・VC++C#/VC#をはじめ他のプログラミング言語にも影響を与えています。

C言語の基本文法

#include "stdio.h" 

#include <stdlib.h> 

 int main ( int argc , char *argv[ ] ) 

 { 

 int i , m ; /* 使わないなら宣言しない */ 

 /* 使うならその前に初期化しよう */ 

 printf ("Hello\n") ;

 return EXIT_SUCCESS ;

 } 

 このCのとてもシンプルなサンプルファイルにはCの文法を知る上でかなり多くの情報が詰まっています。

 このファイルをsample.cとしますが、ソースファイルには、このように任意の名称に拡張子.cを付けます。

 外部からファイルを読み込む場合には、空白を開けずにシャープに[include]という文字列を続けた#include文を使用します。

 Cで#include文を使って読み込むファイルはヘッダファイル(拡張子.h)です。

 指定するヘッダファイル(拡張子.h)はアングルブラケット<>またはダブルクォートで括ります(相違点については後述)。

 int main ( int argc , char *argv[ ] )  { } 

 当然1つのアプリケーションを複数のソースファイルで構成することもできますが、アプリケーションの開始は、main関数であり、アプリケーションに1つだけmain関数が必要でmain関数のあるソースファイルをボディファイルと呼ぶことがあります。

 int main ( int argc , char *argv[ ] ) 

 { 

 } 

 関数定義は、「関数の戻り値の型」(例ではint/integer/整数)、「関数名」、関数名の後に「丸かっこ」( )を伴い、その中にあれば「引数の型」と半角スペースに続けて「引数名」を指定、「複数ある場合はカンマで区切り」、以後コマンド行全体を「波カッコ」{ }で括ります。

 void main ( void )  { } 

 または

 void main ( ) { } 

 mainに限らず関数において戻り値を返さない場合、引数がない場合は、それぞれvoidと指定しますが、引数がない場合書かないこともできますが、その場合も丸かっこは必要です。

 void main ( int argc , char *argv[ ] ) { } 

 関数定義に指定する引数の型と引数のセットを仮引数と呼び、main関数の仮引数を記述する場合は、『 int argc 』と『 char *argv[ ] 』です。

 ( int argc , char *argv[ ] ) 

 引数は丸カッコ内に複数なのでカンマ区切りで指定します。

 『 int argc 』のint型のargcは、引数の数(整数)を保持、『 char *argv[ ] 』のargv[]は、Cにおける配列の記法で、実際の引数のリスト(配列)を保持することになっていますが、このように*がつく場合、実体(この場合リスト)そのものではありません。

 *は、実体が格納されているメモリ(記憶域)上の先頭の位置(アドレス)を指す事を意味するポインタと呼ばれる変数で『*argv[ ]』は、実体である引数のリスト[ ]が格納されているメモリ上の先頭アドレスを指すargvという名のポインタ変数であり、アドレス値が1バイトで収まることがわかっている場合、このようにchar型を指定します。

 『 char *argv[ ] 』を簡潔に言い換えれば、argvは、配列のメモリ先頭位置を指すchar型のポインタです。

 ポインタの考え方は、主に関数間で実体を受け渡すことによる容量や時間的ロスであるオーバヘッドを抑えるのに有効です。

 int i , m ; 

 または 

 int i ; 

 int m ; 

 命令文の行終端はセミコロンで終わらせることになっており、int型の変数iとmを宣言する場合は、まとめて、または個別に宣言することができます。

 int k = 0 ; 

 また、型にもよりますが数値を表す型であれば宣言と同時に初期化することもできます。

 /* */ 

 または

 /* 

 

 */ 

 コメントは単一行、または複数行共に /* と */ の間に記述し、何れもスラッシュとアスタリスクの間にスペースを入れずに続けて記述します。

 Cに限りませんが、ソースコード内にコメント付すことをコメントアウトと呼ぶことがあります。

 /* 

 ボディファイル名:sample.c 

 includeの" "と< >はいずれも利用できるが挙動は処理系(環境・コンパイラ等)定義、他方includeファイルの探索に違いがある点はたいてい共通。 

 (プロンプト上やmakefile内の)コマンドライン上はデフォルト以外の探索パスを指定する場合、< >は -I で指定し、" "は -I- 以降に指定。 

 ヘッダはプリプロセスで処理されるが、" "を指定された検索順で検索した際ファイルが存在しない場合、< >の探索パスを探すことになっている。 

 これらの事情もあり、開発プロジェクトの場合、C標準ヘッダは< >、ユーザー定義ヘッダやC標準以外のヘッダは" "とコーディング規約として定めていることも珍しくない。 

 */ 

 /**************************** 

 適度なコメントは有用である一方、コメントのし過ぎはオーバーコメントとも言われ、避けた方がよい 

 後でソース変更などがあった場合、コメントを修正し忘れると目も当てられない  

 明確な区分けは難しいが、C標準の内容や、そのコード自体わかりきった内容である場合は不要と考えてよいと思う 

 当然、現場ルールで記述する事が決まっているコメントは記述しなければならない事は言うまでもないので書いておく(のはオーバーコメント?) 

 ****************************/ 

 Cでは、変数の他、関数定義と必要に応じた関数原型/プロトタイプ定義、マクロの宣言が可能です。

 Cの標準関数は、ヘッダファイル内で関数定義や関数原型/プロトタイプ定義、マクロの宣言がなされていて、これら必要なヘッダファイルを適宜includeすることによって当該ソースファイルでも利用可能になります。

 冒頭の例では、書式付標準出力関数printfがあるstdio.h、マクロ値EXIT_SUCCESSがあるstdlib.hをincludeしています。

 include時のアングルブラケットとダブルクォートの相違は左記の通りです。

 Cの関数や変数は何も指定しないとスコープ(可視範囲・有効範囲)がグローバルとなりますが、ファイル内に必要な宣言がない場合でも複数のファイルから構成されるプログラムであるケースでは、他のファイルで宣言されている場合があります。

 スコープに関しては、他のファイルでグローバル変数として宣言されていることを明示的に示すextern宣言、ファイル内でのみ有効なローカル変数であることを示すstatic宣言などがあります。

 スコープ指定がなく、関数など{ }内でのみ宣言されている変数は、{ }内でのみ有効です。

 int main ( int argc , char *argv[ ] ) 

 { 

 ... 

 return EXIT_SUCCESS ;

 } 

 ちなみに関数の戻り値の型は、戻り値がない場合はvoid、この例の場合は、EXIT_SUCCESSが、正常終了を表す0、対になるEXIT_FAILUREが異常終了を表すゼロ以外の数値の中で1という定数がセットされることになっているマクロで戻り値が整数値なのでint、もし、char型のポインタならchar(signed char/unsigned char)...etc.となります。

 printf ("Hello\n") ;

 組み込み用途などでOSが存在しないに等しく、利用できるライブラリも環境に依存する場合などを除き、OSが存在し、C標準ライブラリがある環境において実行ファイルを生成する場合には、元になるソースファイル(拡張子.c、複数ある場合は、何れか1つのソースファイル)に必ず唯一1つのmain関数が必要で関数を呼び出す場合には、冒頭の例のように書式付標準出力関数printfなら( )内にstdio.hの中で定義されているprintfが想定する仮引数にあたる値を引数として指定します(が、printfは、かなり柔軟に引数を指定できる関数です)。

 尚、前述のようにmain関数の引数argcにはその引数の数が、argvは引数の配列ですが、argvについては各引数の値の数だけargv[1],argv[2]...,argv[n]の要素として格納され、argv[0]にはプログラム名(実行ファイル名)が入っていることになっており、必要であれば個々に参照することができます。

Cの表記

 Cで使われる表記は、stdio/standard in/out(I/O)/標準入出力、stdlib/standard library/標準ライブラリ、int/integer/整数値、char/character/文字、argc/argument count/引数の数、argv/argument value/引数の値...etc.とUNIX/Linuxやshell、他のスクリプトやプログラミング言語でも見られるように米英語の略語が多用されています。

Cのファイル

 UNIX/Linux Cで一般的なファイルは、次の通りです。

拡張子名称
.cCソースファイル・ボディファイル
.hheader/ヘッダファイル

C言語とコンパイル

$ ls -F 

foo*

 また、gcc等のコンパイラでコンパイルされ生成された実行ファイルはlsコマンドで見ると末尾に*(アスタリスク)が付いた形式になっています(shellはBourne Shell系を想定)。

 この他、コンパイルオプションを指定しない限りコンパイル過程で内部的に生成され、削除される各種ファイルとコンパイル時/実行時にリンクされる静的ライブラリ/共有ライブラリがあります。

C言語とSQL

 更にデータベースを利用する場合には、RDBメーカー及びDB接続方法によってSQL記述ファイル(例えばoracleとCならpro*c/拡張子.pcのファイル)がある場合があります。

C言語とデバッグ

 また、微妙なエラーを探る際や他人が書いた一連のプログラムが一見してもどういう処理をしているのか疑問に思う際、また、プロジェクトが完了して、のちに実運用上問題が発生した場合などにエラー箇所の特定を助けてくれるツールの1つがdbx/gdbなどデバッグを行うデバッガです。

C言語とmakeコマンド/makefile

 cc/gccでのコンパイルも相当に便利ですが、makeコマンドで実行されるmakefile/Makefileを利用すると作業を更に自動化することが可能です。

C言語標準規格

1978年『The C Programming Language』

団体:AT&T/ベル研究所(当時)

共著:ブライアン・カーニハン氏・デニス・リッチー氏/K&R

前者/頭文字kに当たるscript awkの共同開発者3名の内の1人

後者/UNIX開発者の1人&C言語開発者

1989年『ANSI C』

団体:ANSI/American National Standards Institute/米国標準協会

1990年『ISO/IEC 9899:1990』

団体:ISO/International Organization for Standardization/国際標準化機構

1993年『JISX3010』

団体:JIS/Japan Industrial Standard/日本工業規格

 今尚、改訂を経て継続的に標準規格化されているC言語ですが、関数における引数の取り得る数の最低限の規定値、条件分岐のネスト数の最低限の規定値、構造体・共用体のメンバ数の最低限の規定値など規定値を超過した場合や0の除算を行った場合の挙動、そもそも想定外の利用を含め、その際の挙動がC言語で特に定義されていないものや

int i=0; printf("%d %d\n",i++,i++);

の出力結果として、演算子などの優先順位は決まっているものの

0 1

または

1 0

のようにいずれにもなり得る関数の引数における評価順などC言語では特に規定していないケースの挙動については結果的にコンパイラ(場合によってはハードウェアやOS)に依存する部分がありますが、例えばJISでは、実引数の評価順については「未規定の動作」、予期しない結果となる為、禁止されているものの0の除算をした結果については「未定義の動作」として分類されています。

 C言語は、その成り立ちからC言語そのものの文法はもちろん、組み込み系などいわゆるOSが無いケースをも含むシステム環境やコンパイルに使用するコンパイラとの兼ね合いが結果的に強く、よく見るとC言語には文法上、その最終的な結果について規定されていない事項も結構あり、前述のようにC言語で処理すべき範囲の最小値は決まっているが最大値は決まっていない場合などコンパイラに依存する「翻訳限界」があったりしますが、例えばJISでは、前述の「未規定」「未定義」や「処理系定義」「文化圏固有」と国や地域、システム環境やコンパイラによって挙動の異なる事項を分類しています。

 邦訳が難しいところですが、多くの場合、日本語では、implementation-definedやimplementation-definitionを処理系定義、implementation-dependentを処理系依存と訳すことが多いようです。

ホーム前へ次へ