第45回
複数のソースファイルからプログラムを作る~マルチモジュール開発の基本

マルチモジュールのメリット

ソースファイルを複数に分割すると事前設計の手間は増えますが、後々の保守や改良の際に大きなメリットが生じます。

モジュールとは?

本コラムの第35回「変数の通用範囲~内部広域変数と外部広域変数」で、単語検索プログラム“sfind”を複数のソースファイルに分割したマルチモジュールを紹介しました。

モジュールとはいくつかの関数を集めたオブジェクトファイル ※1 で、これがいくつか集まって1つの実行形式ファイル(プログラム)を形成します。

第35回では、モジュールをまたぐ変数の参照などを例に、変数の通用範囲――局所変数と広域変数などを説明することが目的でした。そのため、マルチモジュール開発の詳細については、あえて触れませんでした。

ここで言う「オブジェクト」はオブジェクト指向プログラミングで言うオブジェクトではなく、コンパイラによって機械語に変換された「目的ファイル」のことです

ソースは短い方がいい

第35回でも触れたように、プログラムの規模がある程度大きくなってくると、プログラムのソースを役割別に分割する方が便利になります。デバッグや後の改良などで特定の箇所を探す場合、何千~何万行ものソースファイルが相手だと時間と手間がかかります。エディタの検索機能を使っても、結果が表示されるまでにかなりの時間がかかることもあるでしょう。

何より、ほんの数行、あるいは数文字を書き換えただけなのに、長いソースファイルを再びコンパイルし直す――というのは時間の無駄です。ソースファイルを役割別に分割しておけば、たとえばファイル操作の機能だけを書き換える場合、ファイル操作の機能だけを集めたソースファイルを開いて書き換えればよくなり、作業効率が向上します。

特定の機能だけに絞ったソースは行数も多くなく、そのソースファイルだけを再コンパイルすればよいので、手間も時間も削減できます。

ソース分割の基本

ソースファイルを分割するための考え方の基本は「機能・役割別」です。Cの標準ライブラリ関数も「入出力・数学計算・文字列処理」などのように機能・役割を基準に分割されています。同じように、独自のプログラムでも以下のような形で共通の機能・役割で複数の関数をまとめるのが合理的です。
メイン :main関数とそこから直接呼び出される基本的な関数群
入力  :データの入力と入力されたデータの基本的な処理を行う関数群
内部処理:入力データを演算・加工して新たなデータを生成する関数群
出力  :処理を終えたデータの表示や印刷処理を行う関数群
その他下請け:各種関数から呼び出される下請け的な関数群

入力と出力は、さらに以下のように分割することもできます。
入力
 ファイル入力:ファイルのオープン
 ファイルからのデータの入力
出力
 ファイルへのデータ出力
 画面表示
 プリンタのよる印刷処理

このようにソースファイルを分割しておけば、プリンタを扱う印刷処理だけ、あるいはデータの計算処理だけを書き換える場合に、どのソースファイルを対象とすればよいかが一目瞭然となります。