1

ヘッダー ファイルの内容がプリプロセッサによってソース コード ファイルに複数回挿入されるのを防ぐために、ヘッダー ファイルにヘッダー ガードを含めることを推奨する人がいるのを知っています。

ただし、次のシナリオを検討してください。

ファイルmain.cppstuff.cpp、およびcommonheader.hがあり、.hファイルにはヘッダー ガードがあるとします。

いずれかの.cppファイルがcommonheader.h複数回インクルードしようとすると、プリプロセッサはそれを停止し、オブジェクト コードにコンパイルした後、

main.ocommonheader.h の内容を1 回だけ含む。

stuff.ocommonheader.h の内容を1 回だけ含む。

commonheader の内容はファイル間で繰り返されていますが、同じ.oファイル内では繰り返されていないことに注意してください。

では、リンクの段階で何が起こるのでしょうか? .o ファイルが実行可能ファイルに融合されているため、commonheader の内容が繰り返されていないことを再度確認する必要があります。コンパイラはそれを処理しますか?そうでない場合、巨大なヘッダー ファイルを扱っているときに問題になりません。ファイル間でコードの繰り返しが発生し、実行可能ファイルのサイズが大きくなります。

質問のどこかで概念的な間違いを犯している場合は、修正してください。

4

4 に答える 4

3

通常、ヘッダーファイルは実際にはシンボルを定義するべきではなく、単にそれらを宣言する必要があります。したがって、commonheader.hは次のようになります(インクルードガードを省略):

void commonFunc1(void);
void commonFunc2(void);

その場合は問題ありません。とを呼び出すと、両方とが呼び出さcommonFunc1れたシンボルに対してリンクしたいことがわかり、リンカはそのシンボルを見つけようとします。リンカがシンボルを見つけられない場合、未定義の参照エラーが発生します。の実際の定義は、いくつかのcppファイルにある必要があります。main.cppstuff.cppmain.ostuff.ocommonFunc1commonFunc1

本当にヘッダーファイルで関数を定義したい場合はstatic、リンカがそれらを認識しないように使用してください。したがって、commonheader.hは次のようになります。

static void commonFunc1()
{
    /* ... do stuff ... */
}

この場合、リンカはそれを認識せずcommonFunc1、エラーは発生しません。ただし、これにより実行可能ファイルのサイズが大きくなる可能性があります。おそらく、のコードのコピーが2つになるでしょうcommonFunc1

于 2012-09-01T20:32:49.490 に答える
1

変数をカバーするためにグレイソンの答えを拡張します。ヘッダー ファイルで変数を宣言する場合は、extern キーワードを使用する必要があります。これは、グローバル変数を処理する 1 つの方法です。

ヘッダー ファイル global.h に次のように記述します。

extern Globals globals;

次に、global.h を含む任意のファイルで foo を使用できますが、global.cpp では次のように記述します。

#include "globalstype.h"
Globals globals;

global.cpp に global.h を含める必要はないことに注意してください。ただし、global.cpp が各使用法にコンパイルされていることを確認する必要があります。そうしないと、リンカーからエラーが発生します。

于 2012-09-01T20:49:34.927 に答える
0

通常、ヘッダー ファイルには、決定的なコードではなく、宣言的なコードが含まれています。つまり、一度だけ存在しなければならないものの存在を宣言します。マクロとインライン関数は許可されており、それらが使用される場所では必ず複製されます。

コンパイラは宣言を使用して、未解決のリンク (または参照) をオブジェクト コードに挿入します。リンカーの仕事は、参照を 1 つの定義と一致させることによって、これらのリンクを解決することです。

インクルード ガードを省略した場合、単一の翻訳単位に複数のインクルードがあると、既存のシンボルの複数の宣言に対してコンパイラ エラーが発生します。ただし、誤って定義を含むヘッダーがあり、そのヘッダーが複数の翻訳単位に含まれている場合、定義を持つオブジェクト ファイルが複数存在することになります。代わりに、複数の定義に対してリンカー エラーが発生します。

だからその間:

extern int b ;  // declaration, may occur in multiple translation units

ヘッダファイルにfinがあり、

int b ; // definition, must occur in only object file.

ではありません。

宣言がオブジェクトコードに含まれていないわけではなく、コンパイラーはそれらを使用して、コンパイラーがまだ定義を使用しておらず、解決済みである場合にリンカーが解決する参照を作成します。

于 2012-09-01T20:50:54.677 に答える
0

はい、問題になる可能性があります。複数の定義、または冗長なコピーが作成される可能性があります。

この点で、C は非常に単純です。static、extern、inline があります。コンパイラは、可視性を変更する方法もいくつか定義しています。これの多くは他の回答でカバーされていると思います。

ただし、C++ はまったく異なります。多くの情報があり、暗黙的な定義もあります (たとえば、コンパイラはコピー コンストラクタまたは RTTI を発行する場合があります)。

C++ では、定義がヘッダーに表示される可能性がはるかに高くなります。テンプレート、クラス宣言で定義されたメソッドなどを検討してください。C++ では、デフォルトで One Definition Rule が使用されます。もっと詳しく読みたいと思うでしょうが、基本的には、シンボルのいくつかのカテゴリが複数定義される可能性があると述べています。装飾と宣言の場所/スコープに応じて、多くの場合、リンカーは各本体 (定義) が同一であると想定することが許可されており、遭遇したコピーを自由に破棄できます (バイナリに 1 つの定義を残します)。したがって、コピーを作成するように指定しない限り、これにより、結果のバイナリのサイズが実際に削減されます。

ただし、これらの定義をヘッダーに含めると、コンパイル時間、各ファイルのコンパイルに必要なメモリとファイル、目に見える依存関係が確実に増加し、定義の編集時に再コンパイルする必要があるファイルの数が増加します。

もちろん、この言語は依然として悪い形式を許容しており、何度も何度も何度も述べ、翻訳ごとにコピーしなければならない定義を複数の翻訳に含めても、文句を言うことはありません。その後、確かに多くの膨満感で終わる可能性があります.

これは良い紹介かもしれません: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=386

于 2012-09-01T21:18:12.293 に答える