回答:
適切に使用すると、これは便利なテクニックになります。
かなり小さなパブリックインターフェースと再利用できない多くの実装コードを備えた、複雑でパフォーマンスが重要なサブシステムがあるとします。コードは数千行、100ほどのプライベート関数、そしてかなりのプライベートデータまで実行されます。重要な組み込みシステムを使用している場合は、おそらくこの状況に十分頻繁に対処します。
ソリューションはおそらく階層化され、モジュール化され、分離されます。これらの側面は、サブシステムのさまざまな部分をさまざまなファイルにコーディングすることで効果的に表現および強化できます。
Cを使用すると、これを行うことで多くを失う可能性があります。ほとんどすべてのツールチェーンは、単一のコンパイルユニットに対して適切な最適化を提供しますが、externと宣言されたものについては非常に悲観的です。
すべてを1つのCソースモジュールに入れると、次のようになります。
パフォーマンスとコードサイズの改善-多くの場合、関数呼び出しはインライン化されます。インライン化しなくても、コンパイラーはより効率的なコードを生成する機会があります。
リンクレベルのデータと機能の非表示。
名前空間の汚染とその結果の回避-扱いにくい名前を少なくすることができます。
より速いコンパイルとリンケージ。
ただし、このファイルの編集に関しては、不自然な混乱が生じ、暗黙のモジュール性が失われます。これは、ソースをいくつかのファイルに分割し、これらを含めて単一のコンパイル単位を生成することによって克服できます。
ただし、これを適切に管理するには、いくつかの規則を課す必要があります。これらはある程度ツールチェーンに依存しますが、いくつかの一般的な指針は-
パブリックインターフェイスを別のヘッダーファイルに入れます。これはとにかく行う必要があります。
すべての補助.cファイルを含む1つのメイン.cファイルを用意します。これには、パブリックインターフェイスのコードを含めることもできます。
コンパイラガードを使用して、プライベートヘッダーとソースモジュールが外部コンパイルユニットに含まれないようにします。
すべてのプライベートデータと関数は静的に宣言する必要があります。
.cファイルと.hファイルの概念的な違いを維持します。これは既存の規約を活用します。違いは、ヘッダーに多くの静的宣言があることです。
ツールチェーンに理由がない場合は、プライベート実装ファイルに.cおよび.hという名前を付けます。インクルードガードを使用する場合、これらはコードを生成せず、新しい名前を導入しません(リンク中にいくつかの空のセグメントになる可能性があります)。大きな利点は、他のツール(IDEなど)がこれらのファイルを適切に処理できることです。
大丈夫ですか?はい、コンパイルされます
お勧めですか?no-.cファイルは.objファイルにコンパイルされ、コンパイル後に(リンカーによって)実行可能ファイル(またはライブラリ)にリンクされるため、1つの.cファイルを別の.cファイルに含める必要はありません。代わりにしたいのは、他の.cファイルで使用可能な関数/変数をリストする.hファイルを作成し、.hファイルをインクルードすることです。
番号。
ビルド環境(指定しない)によっては、希望どおりに機能する場合があります。
ただし、*。cをコンパイルすることを期待する多くの環境(IDEと多くの手作りMakefileの両方)があります。その場合、シンボルの重複が原因でリンカーエラーが発生する可能性があります。
原則として、このような行為は避けるべきです。
ソースを絶対に#includeする必要がある場合(通常は回避する必要があります)、ファイルに別のファイルサフィックスを使用します。
私のチームが.cファイルを含めることを決定した状況を共有したいと思いました。私たちのアーキテクチャは、メッセージシステムを介して分離されたモジュールで主に構成されています。これらのメッセージハンドラーはパブリックであり、多くのローカル静的ワーカー関数を呼び出して作業を行います。このプライベート実装コードを実行する唯一の方法は、パブリックメッセージインターフェイスを介して間接的に行われたため、ユニットテストケースのカバレッジを取得しようとしたときに問題が発生しました。一部のワーカー関数はスタック内で少し深いので、これは適切なカバレッジを達成するための悪夢であることが判明しました。
.cファイルを含めることで、テストで興味深いマシンの歯車に到達する方法が得られました。
Linuxのgccコンパイラを使用して、1つの出力で2つのcファイルをリンクできます。2つのcファイルがあり、1つは「main.c」、もう1つは「support.c」です。したがって、これら2つをリンクするコマンドは
gcc main.c support.c -o main.out
これにより、2つのファイルが単一の出力main.outにリンクされます。出力を実行するには、コマンドは次のようになります。
./main.out
support.cファイルで宣言されているmain.cで関数を使用している場合は、externストレージクラスを使用してmainで宣言する必要があります。
.Cまたは.CPPファイルを他のソースファイルに適切に含めることができます。IDEに応じて、通常は右クリックしてプロパティをクリックし、コンパイルする/リンク/ビルドから除外する/チェックを外して/含まれるようにするソースファイルのプロパティを確認して、ダブルリンクを防止できます。多分。または、プロジェクト自体にファイルを含めることができなかったため、IDEはファイルが存在することすら認識せず、コンパイルしようとしません。そして、makefileを使用すると、コンパイルとリンクのためにファイルをそのファイルに入れないだけです。
編集:申し訳ありませんが、他の回答への返信の代わりにそれを回答にしました:(
C言語はそのような#includeを禁止していませんが、結果の翻訳単位は引き続き有効なCである必要があります。
.prjファイルで使用しているプログラムがわかりません。"make"やVisual Studioなどを使用している場合は、個別にコンパイルできないファイルを除いて、コンパイルするファイルのリストを設定してください。
Cファイルを別のファイルに含めることは合法ですが、なぜこれを行うのか、そして何を達成しようとしているのかを正確に知らない限り、行うことはお勧めできません。
あなたが質問の後ろにコミュニティがあなたにあなたの目標を達成するための別のより適切な方法を見つける理由をここに投稿すると確信しています(これはコンテキストが与えられた解決策である可能性があるため、「ほぼ」に注意してください)。
ちなみに私は質問の後半を逃しました。Cファイルが別のファイルにインクルードされ、同時にプロジェクトにインクルードされる場合、オブジェクトをリンクする理由、つまり同じ関数が2回定義される(それらがすべて静的でない場合)ため、シンボルの重複の問題が発生する可能性があります。