同じヘッダー ファイルが C++ プログラムの複数のソース ファイルに含まれている場合、コンパイルにどのような影響がありますか (特にg++ )。
コンパイラはヘッダー ファイルを 1 回だけロードし、ヘッダーを含むソース ファイルごとにコンパイルしますか、それともヘッダー ファイルを含むソース ファイルごとに個別にロードします。
g++: #include
s は、コンパイラ自体ではなく、プリプロセッサによって行われます。g++ の-E
スイッチを使用して、前処理の結果を確認できます。(編集:プリプロセッサは以前は別のものでしたが、現在はコンパイラ実行可能ファイルの一部ですが、この質問に答える目的で、前処理フェーズは依然としてコンパイルプロセスの別個のフェーズです)。
gcc、clang、icc、および msvc では、同じソース ファイル内であっても、各ファイルが検出されるたびにアクセスされます。
これが当てはまらない唯一のケースは、ヘッダー ファイルに#pragma once
ステートメントが含まれている場合です。一部のコンパイラには、インクルード ガードのユーザー向けに同様の最適化があります。
#ifndef THIS_FILE_H
#define THIS_FILE_H 1
/* the stuff in thisfile.h */
#endif
msvc と gcc (およびおそらく clang) でサポートされている「プリコンパイル済みヘッダー」と呼ばれる手法があり、一般的に使用される一連のヘッダーのコンパイル ヘッドを回避するために使用できます。
#include
通常、これは、すべてのs を含む.h または .cpp ファイルを用意することによって行われます。次に、#include
このファイルを各ファイルの最初に追加します (または、「強制インクルード」のアイデアを使用します: msvc では /Fi、gcc では -include)。特定の pch を使用する各ファイルには、同じ定義とコンパイラ オプションが必要です。
次の .h ファイルを記述する場合
// bah.h
"bah",
および次の .cpp ファイル
#include <stdio.h>
const char* words[] = {
"hello",
#include "bah.h"
"world",
#include "bah.h"
#include "bah.h"
NULL
};
int main(int argc, const char* argv[])
{
for (size_t i = 0; words[i] != NULL; ++i ) {
printf("%s\n", words[i]);
}
return 0;
}
出力は次のようになります
こんにちは ばあ 世界 ばあ ばあ
プリプロセッサは、すべてのソース ファイルのマクロ定義を単純に置き換えます。その後、コンパイラは、すべてのソース ファイルを独立したアセンブル ファイルにコンパイルし始めます。このファイルは、アセンブラによってバイナリ マシン コードに変換されます。リンカーは最後に、すべてのオブジェクト ファイルを単一の実行ファイルまたは共有オブジェクトにリンクします。
したがって、基本的に前処理の進行中のコンパイラの仕事ではありません。g++ は、プリプロセッサ、コンパイラ、リンカを含むツールのバンドルです。