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