| プログラムは、ソースコードを実行形式(executable)ファイルに変換することによって作ります。実行形式とは、例えば Windows なら .exe という拡張子のついたファイルのことで、つまりアプリケーションです。ここまでは問題ないですね。 | ||
![]() |
||
| ソースコードから実行形式を作るためには「コンパイル」「リンク」という2つの処理をする必要があります。Visual C++ などのような開発環境を使っている限りはあまり意識する必要がないのですが、実際にはそのようになっています。 | ||
| まず、コンパイルによって、ソースファイルからオブジェクトファイルが作られます。ここで言うオブジェクト(object)は、「目的」という意味です。ちなみに「オブジェクト指向」の object は「もの」と言う意味なので区別しておきましょう。 コンパイルはソースファイルごとに行われます。例えば main 関数から別の関数 f を呼んでいて、その f が main とは別のソースファイルに書かれていたら(つまり分割されていたら)、コンパイルもそれぞれのファイルに対して行います。 | ||
| 次に、オブジェクトをリンクします。リンクとは、実行形式を構成するオブジェクトをひとつにつなぎ合わせることです。このとき、標準関数を使っていればそれらも結合されます。標準関数はコンパイラと一緒に配布されているライブラリファイルに入っているので、リンクのときには必要なライブラリとつなぎ合わせる処理も行われます。 | ||
| ここまでを図解すると、次のようになります。 | ||
![]() |
||
| このように、複数のソースファイルに分けてプログラムを書き、それぞれを別々にコンパイルする方法を「分割コンパイル」と呼びます。大きなプログラムを書くときには(一気に書くのは無理なので)いくつかの部分に分けますが、そのときに必要な方法です。 | ||
|
今度は、オブジェクトファイルに注目してみましょう。それぞれのオブジェクトは
という風に分類できます。例えば上の図のような場合には、main が入っているオブジェクトは f が入っているオブジェクトを必要としています。f が入っているオブジェクトは関数 f を提供しています。ここで、main からできるオブジェクトのファイル名を "main.obj"、f からできるものを "sub.obj" とすると、次のような感じになります。 |
||
![]() |
||
| この例では、f が printf を使っていることを想定しています。printf は標準関数なので、ライブラリに入っています。ライブラリもオブジェクトの一種です(実際にはオブジェクトの集合体です)。あらかじめ標準的な関数をコンパイルしておいてオブジェクトの状態で配布したものがライブラリです。 | ||
| これらのオブジェクトをリンクすると、次のようになります。 | ||
![]() |
||
| これが、実行形式です。・・・と言いたいところですが、実はちょっと違います。最初に実行される関数は main だということになっていますが、厳密にはそれよりも先に「初期化(start up)処理」が入ります。初期化処理では、グローバル変数のクリアや標準入出力のオープンなどが行われ、それから main 関数が実行されます。main 関数を含んだオブジェクトは初期化処理ルーチンに対して main 関数を提供しています。OS から実際に呼ばれるのは初期化処理ルーチンです。 | ||
![]() |
||
|
※
|
C++ では、main を実行する前の初期化の部分の実装はコンパイラの制作者に任されているそうです。main を呼ぶ前に行われるかもしれないし、main の最初で行われるかもしれません。もしかしたら、main は関数ではないかもしれません。それで、プログラマーは main 関数を呼び出してはいけないルールになっています。 | ||
| コンパイルとリンクについて、だいたいのイメージはつかめたでしょうか。この辺の処理は、最近の開発環境なら自動的に行ってくれます。が、中でどういうことが起こっているのかを知ることは大事です。 | ||
| 次回は、分割コンパイルについてもっと詳しくお話しします。 | ||
("Hello, ANOTHER world!" は2001年11月から2002年11月にかけて作成されたコンテンツです。)