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