C++ のコンパイルに時間がかかるのはなぜですか? 質問する

C++ のコンパイルに時間がかかるのはなぜですか? 質問する

C++ ファイルのコンパイルには、C# や Java に比べて非常に長い時間がかかります。C++ ファイルのコンパイルには、通常サイズの Python スクリプトを実行するよりも大幅に長い時間がかかります。現在 VC++ を使用していますが、どのコンパイラでも同じです。なぜでしょうか?

考えられる 2 つの理由は、ヘッダー ファイルの読み込みとプリプロセッサの実行ですが、それだけでは時間がかかる理由を説明できないようです。

ベストアンサー1

いくつかの理由

ヘッダーファイル

コンパイル単位ごとに、数百または数千のヘッダーを (1) ロードし、(2) コンパイルする必要があります。プリプロセッサにより、ヘッダーのコンパイル結果がコンパイル単位ごとに異なる可能性があるため、通常、すべてのヘッダーをコンパイル単位ごとに再コンパイルする必要があります (1 つのコンパイル単位で、ヘッダーの内容を変更するマクロが定義される場合があります)。

おそらくこれが主な理由ですコンパイル単位ごとに膨大な量のコードをコンパイルする必要があり、さらに、すべてのヘッダーを複数回 (それを含むコンパイル単位ごとに 1 回) コンパイルする必要があるためです。

リンク

コンパイルしたら、すべてのオブジェクト ファイルをリンクする必要があります。これは基本的にモノリシックなプロセスであり、並列化することはあまりできず、プロジェクト全体を処理する必要があります。

解析

構文の解析は非常に複雑で、コンテキストに大きく依存し、曖昧さを解消するのが非常に困難です。これには多くの時間がかかります。

テンプレート

C# では、List<T>プログラム内に List のインスタンスがいくつあっても、コンパイルされるのは だけです。C++ では、 はvector<int>とは完全に別の型でありvector<float>、それぞれを個別にコンパイルする必要があります。

これに加えて、テンプレートはコンパイラが解釈しなければならない完全なチューリング完全な「サブ言語」を構成するため、これは途方もなく複雑になる可能性があります。比較的単純なテンプレート メタプログラミング コードでも、数十ものテンプレート インスタンスを作成する再帰テンプレートを定義できます。テンプレートによって、途方もなく長い名前を持つ非常に複雑な型が生成され、リンカーに多くの余分な作業が追加されることもあります (多数のシンボル名を比較する必要があり、これらの名前が数千文字に及ぶ場合、かなりコストがかかる可能性があります)。

そしてもちろん、テンプレートは一般にヘッダーで定義する必要があるため、ヘッダー ファイルの問題が悪化します。つまり、コンパイル単位ごとにはるかに多くのコードを解析してコンパイルする必要があります。プレーンな C コードでは、ヘッダーには通常、前方宣言のみが含まれており、実際のコードはほとんどありません。C++ では、ほぼすべてのコードがヘッダー ファイルに存在することは珍しくありません。

最適化

C++ では、非常に劇的な最適化が可能です。C# や Java ではクラスを完全に削除することはできません (リフレクションの目的でクラスが存在する必要があります)。ただし、単純な C++ テンプレート メタプログラムでも、数十または数百のクラスを簡単に生成できます。これらのクラスはすべて、最適化フェーズでインライン化されて再び削除されます。

さらに、C++ プログラムはコンパイラによって完全に最適化される必要があります。C# プログラムは JIT コンパイラに依存してロード時に追加の最適化を実行できますが、C++ にはそのような「2 度目のチャンス」はありません。コンパイラが生成するものは、可能な限り最適化されます。

機械

C++ はマシン コードにコンパイルされますが、これは Java や .NET が使用するバイトコードよりも多少複雑になる場合があります (特に x86 の場合)。(これはコメントなどで言及されていたため、完全性を保つために言及しただけです。実際には、この手順は総コンパイル時間のほんの一部しかかからないでしょう)。

結論

これらの要素のほとんどは C コードにも共通しており、C コードは実際かなり効率的にコンパイルされます。C++ では解析手順がはるかに複雑で、かなり長い時間がかかりますが、主な原因はおそらくテンプレートです。テンプレートは便利で、C++ をはるかに強力な言語にしますが、コンパイル速度の点でも悪影響を及ぼします。

おすすめ記事