1 ファイル 1 関数主義
今から8年半ほど前、今はなき月刊誌「Cマガジン」に、「プログラミングの禁じ手 C言語編」というのが掲載されていました。その後も比較的長期にわたってCマガジンのウェブサイトに掲載されていたのですが、現在ではそれも削除されてしまっています*1。その後、「Cマガジン」に掲載された類似の記事を再編集した「すべてのプログラマに効く 危険なプログラムの処法箋」という書籍が出ていますので、興味のある方はご覧になられるとよいでしょう。
さて、それでは今回の本題である1ファイル1関数主義についてお話しましょう。先ほどご紹介した「Cマガジン」の記事では、1ファイル1関数主義を禁じ手として挙げています。すなわち、ひとつのファイルにはひとつの関数定義しか記述してはいけないというルールを徹底しようとすると、本来関数を分割すべきところでもファイルを分割するのが面倒なため関数が肥大化すること、グローバル変数が多発することになることを原因として挙げています。
なるほど一理あります。しかし、ライブラリの開発にかぎれば、1ファイル1関数主義を原則とする方が望ましいのです。そうしなければ、アプリケーションから決して呼出すことのない関数が大量にリンクされてしまい、プログラムサイズの増大につながるからです。ただし、次のようなケースでは、1ファイルに複数の関数定義を記述してもよいでしょう。
必ず一緒に使うべき関数
例えば、リソースの獲得と解放のような、必ずセットで使用しなければならない関数であれば、同じファイルにそれぞれの関数定義を入れても問題ないでしょう。ただ、malloc と free は対で使いますが、メモリの割り付け方法は、malloc 以外にも calloc や realloc もあることを忘れてはなりません。このような場合は、必ず一緒に使う組み合わせというのがありませんので、同じファイルに一緒に記述することは可能なかぎり避けるべきです。
内部的に呼出す下請け用の関数
1ファイル1関数主義といっても、「1関数」の基準はあくまでも公開すべき関数という意味です。ですから、あまり関数が大きくなるようであれば、適当に分割してファイル内で完結させることは問題ありません。それは、関数の実装上の都合でしかないからです。
インライン関数と関数テンプレート
インライン関数や関数テンプレートは、実際に呼出したものだけが実体化されますので、ヘッダファイル内に複数の関数を詰めこんでも問題ありません。C++では、可能であればこの方法を採用するのが理想的であることが多いはずです。
1ファイル1関数主義を原則とする理由は、決して呼出されない関数がリンクされることを回避するためです。そのことを理解しておけば、目的と手段を混同した無意味なコーディング規約に悩まされることはないでしょう。
*1 ここにアーカイブが残っています。


最近のコンパイラは、最適化の際に使用していない関数をリンクから
除外してくれると思っていたのですが、そんなことはないのでしょうか?
すいません、言葉足らずでした。 一ファイル内
すいません、言葉足らずでした。
一ファイル内に複数の関数を記述して、ライブラリファイルを作成し
そのライブラリファイルをリンクして実行バイナリを作成した際、
最近のコンパイラの最適化では、実行バイナリ内に使用していない関数が入ることは
ないと考えていたのですが、そのようなことはないのでしょうか?
コメントありがとうございます。
統計を取っていないので正確なことはいえませんが、最近のコンパイラでもそうした最適化が働くものは必ずしも多数派ではないと考えています。
また、そうした最適化が使える場合でも、未使用の関数を削除する機能はリンカオプションに依存するはずです。リンカオプションはアプリケーション側で設定しますので、ライブラリではコントロールすることができません。
そして、それらの問題をクリアしたとしても、特定処理系の最適化機能に依存した設計を行うのは好ましくないでしょう。
なるほど、ありがとうございます。
なるほど、ありがとうございます。