web-dev-qa-db-ja.com

C ++での複数のファイルのコンパイルとリンク

私の「プログラマーではない」友人の1人が最近、複雑な機械的問題を解決するC++プログラムを作成することを決めました。

彼は各関数を個別の.cppファイルに記述し、次のようにそれらをすべてメインのソースファイルに含めました。

main.cpp:

#include "function1.cpp"
#include "function2.cpp"
...
int main() 
{
...

}

次に、コードをコンパイル、gccの1行を使用します。

g++ main.cpp    // took about 2 seconds 

さて、これでうまくいくことはわかっていますが、.cppファイルをメインプログラムに直接インクルードすることが良いアイデアかどうかはわかりません。次のスキームを何度か見ましたが、すべての関数プロトタイプは、次のように、externキーワードを使用してヘッダーファイルに入ります。

funcs.h:

extern void function1(..);
extern void function2(..);
...

main.cpp:

...
#include "funcs.h"
...

&コンパイル:

g++ -c function1.cpp
g++ -c function2.cpp
...
g++ -c main.cpp
g++ -o final main.o function1.o function2.o ...

この方法の方が良いと思います(Makefileを使用するのはもちろんです)。友達に彼を説得するのにどのような理由がありますか?

21
user191776

オブジェクトごとにオブジェクトをコンパイルする主な理由は、時間を節約するためです。高レベルのローカライズされたコードの変更では、多くの場合、1つのオブジェクトのコンパイルと再リンクのみが必要です。 (ヘッダーのヒープに描画するオブジェクトが多すぎたり、同じテンプレートを重複してインスタンス化したりすると、一般的なコードの変更により完全な再コンパイルがトリガーされると、実際には遅くなる可能性があります)。

プロジェクトが2秒でコンパイルできるほど小さい場合、従来のアプローチには実際のメリットはあまりありませんが、期待されていることを実行すると、開発者の時間を節約できます。バランスを取るには、メイクファイルの保守にも時間がかかりますが、インクルードディレクトリ、ライブラリ、コンパイラスイッチなどを簡単にキャプチャするために、とにかくそうすることになるでしょう。

記述/生成されたコードへの実際の影響:

  • cppファイルには通常、最初に独自のヘッダーが含まれます。これにより、ヘッダーコンテンツが他のクライアントコードによって独立して使用できるかどうかの健全性チェックが提供されます。すべてをまとめると、名前空間は以前のヘッダー/実装ファイルからのインクルードですでに「汚染されています」
  • すべてが1つの翻訳単位内にある場合、コンパイラーは最適化する可能性があります(leppieのコメントに対して+1、同じことを行う...)
  • 静的な非メンバー変数と匿名の名前空間は翻訳単位にプライベートであるため、複数のcppを含めると、これらを共有することになります。
  • cppファイルがヘッダーで言及されておらず、匿名の名前空間または静的である可能性がある関数または変数を定義していると言います。翻訳ユニットの後のコードは、独自の前方宣言をハックする必要なく自由に呼び出すことができます(これは悪いことです) -関数がそれ自体のcppの外部で呼び出されることを意図していた場合、それはヘッダー内にあり、その翻訳単位のオブジェクト内で外部に公開されたシンボルであったはずです)

ところで、C++では、ヘッダーはexternキーワードを明示的に使用せずに関数を宣言できますが、それは通常のことです。

21
Tony Delroy

2番目のスタイルの理由は、各.cppファイルを、独自のクラス、グローバル変数などを使用して、競合のリスクなしに個別に処理できるためです。

すべての.cppファイル(MSVCなど)を自動的にリンクするIDEの方が簡単です。

6