web-dev-qa-db-ja.com

C ++でヘッダーファイルを2回インクルードする

iostreamまたはその他のヘッダーファイルをファイルに2回インクルードするとどうなりますか?コンパイラがエラーをスローしないことは知っています。

コードは2回追加されますか、それとも内部で何が起こりますか?

ヘッダーファイルをインクルードすると実際に何が起こりますか?

15
user1743613

ガードを含む ファイルの内容がコンパイラによって実際に2回表示されるのを防ぎます。

インクルードガードは基本的に、ヘッダーファイルの最初と最後にあるプリプロセッサの条件付きディレクティブのセットです。

#ifndef SOME_STRING_H
#define SOME_STRING_H

//...

#endif 

ここで、ファイルを2回インクルードすると、最初のラウンドマクロSOME_STRING_Hが定義されないため、ファイルの内容が処理され、コンパイラによって表示されます。ただし、#ifdefの後の最初のものは#defineであるため、SOME_STRING_Hが定義され、次回のラウンドではヘッダーファイルのコンテンツはコンパイラに表示されません。

衝突を回避するために、インクルードガードで使用されるマクロの名前は、ヘッダーファイルの名前に依存するようになっています。

14
Adam Zalcman

ヘッダーファイルは単純な獣です。あなたが#include <header>発生するのは、headerの内容が基本的にファイルにコピーアンドペーストされることだけです。ヘッダーが複数回含まれるのを防ぐには、include guardsが使用されているため、ほとんどのヘッダーファイルに次のようなものが表示されます。

#ifndef SOME_HEADER_FILE_GUARD 
#define SOME_HEADER_FILE_GUARD

//Contents of Header

#endif
3
Yuushi

次の行に沿ったプリプロセッサコードのため、単にスキップされます。

#ifndef MY_HEADER_H
#define MY_HEADER_H

<actual header code here>

#endif

したがって、2回含めると、MY_HEADER_Hはすでに定義されており、#ifndef#endifの間のすべてがプリプロセッサによってスキップされます。

2
Darhuuk

場合によります。 <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で始まるインクルードガードを使用します(これは、ユーザーコードの正当な記号ではありません)。これらのオプションは必ずしも利用できるとは限りません。

1
James Kanze