C言語では、複数のソースファイルを結合して、一つの実行可能ファイルを作成することができます。
実行可能ファイルが作られる過程は、次のようになります。
step1:コンパイル それぞれのソースファイルを個別にコンパイルします。
これにより通常はソースファイルそれぞれのオブジェクトファイルが作られます。
(よく使われるオブジェクトファイルの拡張子は .obj です)
step2:リンク step1で作成されたオブジェクトファイルと、 作品の種類に応じて使う他のファイルをまとめて、 作品の実行可能ファイルが作られます。
以上のように複数のソースファイルをコンパイルしてオブジェクトファイルを作成し、
これらを結合して一つの実行可能ファイルを作成するわけです。
この具体的な手法は、開発環境によりさまざまです。
近年の開発環境では、作成する作品一つに対してプロジェクトと呼ばれるものを作り、
それで作品の元になる複数のソースファイルやオブジェクトファイルを管理させ、
ビルドと呼ばれる操作により一括して作成する形態のものが多いようです。
Microsoft→
Visual Stadio 2003の例
分割する最も大きな理由は、関数を再利用しやすくするためです。
そこで、他の作品でも再利可能な関数が存在してmain関数が存在しないソースファイル(
cfunc.c)と、
main関数が存在してcfunc.cの関数を呼び出すソースファイル(
Afunc.c)に分割し、それを結合して、
A.exeの作品を作るように作成します。このイメージを以下に示します。
なお、cfunc.cにもmainが存在すると、
Afunc.cのmainと重複してリンクエラーが
指摘されます。
さて今度は、この(cfunc.c)を再び利用して、
別のソースファイルBfunc.c)と結合し、
B.exeの作品を作るイメージを以下に示します。
このように、うまく分割できれば、cfunc.cを
利用することにより、労を少なくして作ることができます。
このように、別のファイルにあるグローバル変数やグローバル関数を利用する場合は、
extern宣言を必要とします。
externは、『外側の〜』という意味で、C言語の宣言に使うキーワードです。
これで宣言子した変数や関数は、宣言したソースファイルの記述位置以降で、
その宣言した名前(識別子)を
利用できるようになります。
ただし、他のファイルで実際に存在しないとリンクエラーになります。(逆に重複して存在すると、やはりリンクエラーになります。)
また、実在する宣言と一致していないとエラーになります。
このextern宣言は、変数や配列の記憶域を用意させる指示でなく、他のファイルにある記憶域であっても、
それを利用できるようにするための指示です。配列の場合では、[ ]の中のサイズを書きません。
なお、関数はexternを省略でき、それがこれまで使ってきたプロトタイプ宣言です。
以下に具体的な例を示します。まず、cfunc.cの例です。
#include <stdio.h> #define ISIZE 512 /* 配列の要素数 */ #define FILE_IA "iarray.txt" /* 扱うファイルのパス */ int iarray[ISIZE]; /* データを記憶する配列 */ int icount; /* データ個数 */ /* 数字でないキー入力まで、配列へ追加入力する。 同時にicountを更新*/ void input_ia() { while( icount < ISIZE ) { printf("%d:DATA>", icount); if( fscanf(stdin, "%d", iarray + icount) != 1) break; icount++; } fflush(stdin); } /* 配列のデータをすべて(iarray[0]からiarray[icount-1]の要素)表示する。*/ void disp_ia() { int i = 0; while( i < icount ) { printf("%d:%d\n", i, iarray[i]); i++; } } /* main関数は定義しない */
上記のcfunc.cを利用 して、次のように実行させます。
そのためのcfunc.cを利用した
のファイルは、次のようになります。
(作品を作る場合には、この2つを結合させる指示をすることになります。)
なお、関数プロトタイプにおける extern の記述は省略してもよいことになっています。
上記のcfunc.cを利用する別の作品例へ、
のボタンで切り替えてみましょう。
Visual Stadio 2003プロジェクトの例→