web-dev-qa-db-ja.com

一部のCプログラムが1つの巨大なソースファイルで記述されているのはなぜですか?

たとえば、過去の SysInternals ツール "FileMon"には、カーネルモードドライバーがあり、そのソースコードは完全に1つの4,000行のファイルに含まれています。これまでに書かれた最初のpingプログラムと同じ(〜2,000 LOC)。

91
Bran

複数のファイルを使用すると、常に追加の管理オーバーヘッドが必要になります。コンパイルスクリプトとリンクステージが別々になっているビルドスクリプトやメイクファイルをセットアップし、さまざまなファイル間の依存関係が正しく管理されていることを確認し、電子メールまたはダウンロードでソースコードを簡単に配布できるように「Zip」スクリプトを記述します。オン。今日の現代のIDEは通常、その負担の多くを占めますが、最初のpingプログラムが作成された時点では、そのようなIDEは利用できませんでした。そして、そのファイルについては小さい〜4000 LOCのように、このようなIDEがなければ、複数のファイルを適切に管理します)、前述のオーバーヘッドと複数のファイルを使用することの利点の間のトレードオフは、人々が決定を下す可能性がありますシングルファイルアプローチの場合。

143
Doc Brown

Cはモジュール化が得意ではないからです。乱雑になり(ヘッダーファイルと#include、extern関数、リンク時のエラーなど)、さらに多くのモジュールを組み込むほど、扱いが難しくなります。

より最近の言語は、Cの過ちから学んだため、より優れたモジュール化機能を備えており、コードベースをより小さく単純なユニットに簡単に分解できます。しかし、Cを使用すると、あまりにも多くのコードと見なされるものを単一のファイルにまとめることを意味する場合でも、そのすべての問題を回避または最小化することは有益です。

80
Mason Wheeler

歴史的な理由とは別に、これを最新のパフォーマンス重視のソフトウェアで使用する理由が1つあります。すべてのコードが1つのコンパイル単位にある場合、コンパイラーはプログラム全体の最適化を実行できます。個別のコンパイル単位では、コンパイラーはプログラム全体を特定の方法で最適化できません(たとえば、特定のコードのインライン化)。

リンカは、コンパイラが実行できることに加えて、いくつかの最適化を実行できますが、すべてではありません。たとえば、最近のリンカは、複数のオブジェクトファイル間でさえ、参照されていない関数を除外するのに本当に優れています。それらは他のいくつかの最適化を実行することができるかもしれませんが、コンパイラーが関数内で実行できることのようなものは何もありません。

シングルソースコードモジュールのよく知られた例の1つはSQLiteです。詳細については SQLite Amalgamation ページを参照してください。

1。エグゼクティブサマリー

100を超える個別のソースファイルが「sqlite3.c」という名前のCコードの1つの大きなファイルに連結され、「アマルガメーション」と呼ばれます。統合には、アプリケーションがSQLiteを埋め込むために必要なすべてのものが含まれています。融合ファイルは180,000行を超える長さで、サイズは6メガバイトを超えます。

SQLiteのすべてのコードを1つの大きなファイルに結合すると、SQLiteの展開が容易になります。追跡するファイルは1つだけです。また、すべてのコードが単一の翻訳単位に含まれているため、コンパイラーはプロシージャー間の最適化を改善して、マシンコードを5%から10%高速化できます。

37
user22815

他の回答者が述べた単純さの要素に加えて、多くのCプログラムは1人の個人によって書かれています。

個人のチームがある場合、コードの変更における不当な競合を回避するために、アプリケーションをいくつかのソースファイルに分割することが望まれます。特に、プロジェクトに取り組んでいる上級プログラマーと非常にジュニアプログラマーの両方がいる場合。

一人で作業している場合は問題ありません。

個人的には、習慣的なものとして、機能に基づいて複数のファイルを使用しています。しかし、それは私だけです。

15
Ron Ruble

C89にはinline関数がなかったためです。つまり、ファイルを関数に分割すると、スタックに値をプッシュしてジャンプするオーバーヘッドが発生しました。これにより、1つの大きなswitchステートメント(イベントループ)でコードを実装する場合と比べて、かなりのオーバーヘッドが追加されました。ただし、イベントループは、モジュール化されたソリューションよりも効率的に(または正しく)実装することが常にはるかに困難です。そのため、大規模なプロジェクトの場合、モジュール化をオプトアウトすることになります。しかし、事前に考え抜かれた設計があり、1つのswitchステートメントで状態を制御できるとき、彼らはそれを選択しました。

今日では、C内でも関数をインライン化できるため、モジュール化するためにパフォーマンスを犠牲にする必要はありません。

2

これは進化の例として数えられますが、まだ言及されていないことに驚いています。

プログラミングの暗い日には、単一のFILEのコンパイルには数分かかる場合があります。プログラムがモジュール化されている場合、必要なヘッダーファイル(プリコンパイル済みヘッダーオプションなし)を含めると、速度がさらに低下する大きな原因になります。さらに、コンパイラーは、ディスク自体にいくつかの情報を保持することを選択または必要とする場合がありますが、おそらく自動スワップファイルの利点はありません。

これらの環境要因が進行中の開発慣行に引き継がれ、徐々に徐々に適応してきた習慣。

当時、単一のファイルを使用することによる利益は、HDDの代わりにSSDを使用することで得られるものと同様です。

1
itj