1

Cプログラムをコンパイルするときは、簡単にするために、最後に特定のヘッダーのソースファイルを含めています。したがって、main.cにutil.hが含まれている場合、util.hには、util.cが使用するすべてのヘッダー、アウトラインタイプ、構造体などが含まれ、最後にutil.cが含まれます。次に、コンパイルするときにgcc main.c -o mainを使用するだけで、残りはすべて処理されます。

私はCコーディング標準を調べて、物事を行うための最良の方法を見つけようとしてきましたが、非常に多くの、そして非常に多くの矛盾する意見があり、私は何を考えるべきかわかりません。多くの場所で、オブジェクトファイルをすべてWebに含めるのではなく、個別にコンパイルすることをお勧めするのはなぜですか?utilはutil.c以外には触れないので、この2つは完全に独立しており、理論的には(私の理論では)問題ありませんが、これはコンピューターサイエンスであり、正しい場合でも人々は間違っているため、おそらく間違っています。ですから、私がすでに間違っているのなら、私はおそらく間違っています。

一部の人々は、ヘッダーファイルはプロトタイプのみである必要があり、ソースファイルはそれを含むものであり、必要なシステムヘッダーであると言います。純粋に美的観点から、ヘッダー(この場合はutil.h)にすべての情報(タイプ、使用されるシステムヘッダー、プロトタイプ)を含め、util.cに関数コードのみ(1つの「#include」を除く)を含めることをお勧めします。一番上にあるutil.h"")。

私が得ているポイントは、これらすべてが機能しているので、方法を選択することは、背景(私)を理解していない人にとっては恣意的に聞こえることだと思います。理由と内容を教えてください。

4

5 に答える 5

6

プログラムは小さいですが、これは機能します。ただし、ある時点で、プログラムが十分に大きくなるため、1行を変更するたびにプログラム全体を再コンパイルするのは後部の苦痛です。

これは、巨大なファイルの編集を回避するだけでなく、プログラムを分割する理由です。main.cとutil.cが別々にオブジェクトファイルにコンパイルされている場合、main.cの関数の1行を変更しても、util.cのすべてのコードを再コンパイルする必要はなくなります。

プログラムが数十のファイルで構成されているときまでに、これは大きな勝利になります。

于 2013-01-31T23:25:39.223 に答える
1

重要なのは、そのファイルを独立させるために必要なものだけを含めたいということです。これにより、コンパイラが必要なヘッダーのみを読み取ることができ、必要がない場合はすべてのヘッダーを繰り返し読み取ることができるため、全体的なコンパイル時間が短縮されます。たとえば、util.cメソッドが関数や型を使用している<stdio.h>が、使用してutil.hいない場合は、コンパイラがコンパイルするときにのみ<stdio.h>インクルードするようにインクルードしますが、 代わりにインクルードする場合は、すべてのソースファイルをインクルードします。これには、それが必要かどうかも含まれます。util.cutil.c<stdio.h><stdio.h>util.hutil.h<stdio.h>

これは、ほんの一握りのファイルしかない小さなプロジェクトではごくわずかですが、適切なヘッダーを含めると、大きなプロジェクトのコンパイル時間に影響を与える可能性があります。

「オブジェクトファイル」に関する質問に関して:ソースファイルをオブジェクトファイルにコンパイルするとき、ビルドシステムが古いオブジェクトファイルを持つソースファイルのみを再コンパイルできるようにするショートカットを作成します。これは、特に大規模なプロジェクトの場合、コンパイル時間を大幅に短縮するための効果的な方法です。

于 2013-01-31T23:23:09.597 に答える
1

まず、.hファイルから.cファイルをインクルードすることは完全に低音です。

それを行う「標準的な」方法は、大まかに次のような考え方に従います。

数十の関数を含むライブラリがあります。すべてを1つの大きなソースファイルに保持するということは、ライブラリの1つの関数だけを使用している場合でも、ライブラリを使用する人は誰でもライブラリ全体をリンクする必要があることを意味します。(C標準ライブラリ全体をリンクすることを想像してみてくださいputs( "Hello" )。)

したがって、個別にコンパイルされた複数のソースファイルに分割します。関数の1つに変更を加えるときはいつでも、毎回すべてを再翻訳するのではなく、1つの小さなソースファイルのみを再翻訳し、ライブラリアーカイブ(または実行可能ファイル)を更新する必要があります。(コードサイズがCPUの改善にいくらか追いついているため、これはまだ問題です。Boostlibのようなものをコンパイルすることは、それほど派手でないハードウェアではまだ数分かかることがあります...)

しかし、今あなたはピンチにいます。関数は.cファイル内で定義され、対応する.oファイルは便利にリンクできます(必要に応じて.aアーカイブを介して)。ただし、別のソースファイル(別名「変換ユニット」)から関数(.oファイルによって提供される)を実際に適切にアドレス指定するには、コンパイラが関数名、そのパラメータリスト、およびその戻り型を知っている必要があります。これが、関数の宣言(つまり、本体のない関数ヘッド)が別のヘッダー(.h)ファイルに入れられる理由です。

他のソースファイル#includeはヘッダーファイルになり、関数を適切にアドレス指定でき(コンパイラは関数が実際に何をするかを認識しません)、ライブラリ/プログラムのすべての部分が.oファイルにコンパイルされるとすべてがリンクされます。

ソースファイルには、基本的に2つのファイルが関数宣言で一致することを確認するための独自のヘッダーが含まれています。;-)

私が今それを書くのをわざわざすることができる限り、それはそれについてです。すべてを1つのモノリシックソースファイルに入れることはほとんど受け入れられません(実際には、そうではありません。約200行を超えるものではありません)が、.hファイルの最後に.cファイルを含めることは、Cコーディングを学習したことを意味します。良い本の代わりにひどいコードを見たり、指導した人は誰でも、彼の人生でCコーディングについて他の人を指導してはいけません。犯罪は意図されていません。;-)

PS:ヘッダーファイルは、コードの一部の優れた要約/監視も提供します。ヘッダーを提供しない言語(Javaなど)では、この種の情報を抽出するためにIDEまたはドキュメントツールが必要です。個人的には、ヘッダーファイルは負債ではなく利益であることがわかりました。

于 2013-01-31T23:29:30.797 に答える
0

慣例としてファイルを使用*.hしてください。ファイルはファイル内にあります。マクロ定義、データ型宣言、関数宣言、およびデータ宣言のみが含まれます。すべての定義はファイルにあります。それが、他の誰もがCプログラムを組織する方法です。あなたの仲間の人間(いつかあなたのプログラムを理解する必要があるかもしれません)に恩恵を与えてください。inが外部で使用されている場合は、そのファイル内のすべての宣言を含むものを外部で使用するように記述し、それをin (宣言と定義が一致することを確認するため)およびすべての使用ファイルに含めます。の束が常にある場合*.c*.h#include*.c*.hextern*.cfile.cfile.hfile.c*.c*.h一緒に含めると、への分割*.cが正しくないことを意味する場合があります(または、少なくとも*.h;の分割を行う必要があります。おそらく.h、これらすべての宣言を含め*.h、関連ファイルのグループ間で必要に応じて内部使用のために作成する必要があり*.cます)。

[あなたが概説するように書かれたプログラムが私の道を横切るならば、私は疫病のようにそれを避けることをあなたに保証することができます。余分な難読化はIOCCCでうまくいくかもしれませんが、私はそうではありません。これは、プログラムをきれいに整理する方法を知らない人の確かな兆候であるため、プログラムを試す価値はないでしょう。]

Re:個別のコンパイル: Cプログラムを分割して、断片を理解しやすくし、Cファイルでの動作の詳細を非表示にすることができます(think static)。これにより、Parnasのモジュール性がサポートされます。また、ファイルを変更した場合でも、すべてを再コンパイルする必要はありません。

Re:異なるCプログラミング標準:はい、周りにはたくさんあります。快適に感じるものを選び、それに固執します。プロジェクトに取り組む場合は、その基準を順守してください。

于 2013-01-31T23:47:48.920 に答える
0

「単一の翻訳ユニットに含める」アプローチは、非常にサイズの大きいプロジェクトでは非常に非効率的になり、複数の開発者に分散しているプロジェクトでは実用的ではありません。

静的ライブラリを作成するとき、ライブラリ内のすべてが単一の変換ユニットからのものである場合、それにリンクされているコードは、参照されているかどうかに関係なく、すべてのライブラリコードを取得します。

makeなどのビルドマネージャーまたはほとんどのIDEで使用可能な機能を使用するプロジェクトは、ヘッダーファイルの依存関係を使用してインクリメンタルビルドを可能にします。変更された、または変更されたファイルに依存するソースのみをコンパイルします。依存関係はファイルインクルードによって決定されるため、冗長な依存関係を最小限に抑えるとビルド時間が短縮されます。

典型的な商用プロジェクトは、数十万行のコードと数百のソースファイルで構成されます。完全な再構築時間は、数分から数時間までさまざまです。開発サイクルでコードの変更とテストの間にそれほど長く待たなければならない場合、生産性は非常に低くなります。

于 2013-02-01T00:24:18.490 に答える