iostream
またはその他のヘッダーファイルをファイルに2回インクルードするとどうなりますか?コンパイラがエラーをスローしないことは知っています。
コードは2回追加されますか、それとも内部で何が起こりますか?
ヘッダーファイルをインクルードすると実際に何が起こりますか?
ガードを含む ファイルの内容がコンパイラによって実際に2回表示されるのを防ぎます。
インクルードガードは基本的に、ヘッダーファイルの最初と最後にあるプリプロセッサの条件付きディレクティブのセットです。
#ifndef SOME_STRING_H
#define SOME_STRING_H
//...
#endif
ここで、ファイルを2回インクルードすると、最初のラウンドマクロSOME_STRING_H
が定義されないため、ファイルの内容が処理され、コンパイラによって表示されます。ただし、#ifdef
の後の最初のものは#define
であるため、SOME_STRING_H
が定義され、次回のラウンドではヘッダーファイルのコンテンツはコンパイラに表示されません。
衝突を回避するために、インクルードガードで使用されるマクロの名前は、ヘッダーファイルの名前に依存するようになっています。
ヘッダーファイルは単純な獣です。あなたが#include <header>
発生するのは、header
の内容が基本的にファイルにコピーアンドペーストされることだけです。ヘッダーが複数回含まれるのを防ぐには、include guards
が使用されているため、ほとんどのヘッダーファイルに次のようなものが表示されます。
#ifndef SOME_HEADER_FILE_GUARD
#define SOME_HEADER_FILE_GUARD
//Contents of Header
#endif
次の行に沿ったプリプロセッサコードのため、単にスキップされます。
#ifndef MY_HEADER_H
#define MY_HEADER_H
<actual header code here>
#endif
したがって、2回含めると、MY_HEADER_H
はすでに定義されており、#ifndef
と#endif
の間のすべてがプリプロセッサによってスキップされます。
場合によります。 <assert>
を除いて、標準では、標準ヘッダーの2番目(およびそれ以降)のインクルードがno-opである必要があります。ただし、これはヘッダーの特性です。コンパイラーは、インクルードに遭遇するたびに、(少なくとも概念的には)すべてのヘッダーテキストを読み取ってインクルードします。
このような場合に複数の定義を回避するための標準的な方法は、インクルードガードを使用することです。ヘッダー内のすべてのC++コードは次のように囲まれます。
#ifndef SPECIAL_NAME
#define SPECIAL_NAME
// All of the C++ code here
#endif SPECIAL_NAME
明らかに、各ヘッダーには異なる名前が必要です。アプリケーション内では、通常、ファイル名と場所に基づいて規則を確立できます。 subsystem_filename
のようなもので、C++シンボルで無効な文字(ファイル名で使用している場合)がマップされています(多くの場合、すべて大文字です)。ライブラリの場合、ベストプラクティスは、適度に長いランダムな文字シーケンスを生成することです。はるかに頻繁に(実装の品質の観点からは確かに劣りますが)、そのようなすべてのシンボルが文書化されたプレフィックスで始まるようにすることです。
もちろん、システムライブラリでは、ここで予約済みの記号(たとえば、アンダースコアで始まり大文字が続く記号)を使用して、競合がないことを保証できます。または、まったく異なる実装依存の手法を使用することもできます。たとえば、Microsoftはコンパイラ拡張機能#pragma once
を使用しています。 g ++は、常に_GLIBCXX
で始まるインクルードガードを使用します(これは、ユーザーコードの正当な記号ではありません)。これらのオプションは必ずしも利用できるとは限りません。