web-dev-qa-db-ja.com

ヘッダーファイルの変数定義

[〜#〜] c [〜#〜]とコンパイルプロセスに関する私の非常に基本的な知識は最近錆びています。次の質問に対する答えを見つけようとしていましたが、コンパイル、リンク、および前処理フェーズの基本を接続できませんでした。グーグルでのクイック検索もあまり役に立ちませんでした。だから、私は究極の知識の源に来ることにしました:)

私は知っています:変数は.hファイルで定義されるべきではありません。そこで宣言しても大丈夫です。

Why:ヘッダーファイルが複数の場所からインクルードされる可能性があるため、変数を複数回再定義します(リンカーはエラーを出します)。

考えられる回避策:ヘッダーファイルでヘッダーガードを使用し、その中で変数を定義します。

それは本当に解決策ですか:いいえ。ヘッダーガードは前処理フェーズ用であるためです。これは、この部分がすでに含まれていることをコンパイラーに通知し、再度含まないようにすることです。しかし、複数定義のエラーは、コンパイルのかなり後にリンカー部分で発生します。

このすべてが、前処理とリンクがどのように機能するかについて私を混乱させました。ヘッダーガードシンボルが定義されている場合、前処理にはコードが含まれないと思いました。その場合、変数問題の複数の定義も解決されるべきではありませんか?

これらの前処理ディレクティブにより、コンパイルプロセスがヘッダーガードの下でシンボルを再定義する必要がなくなりますが、リンカーはシンボルの複数の定義を取得します。

25
Methos

ヘッダーガードは、複数のソースファイルからではなく、単一のソースファイルに複数含まれることからユーザーを保護します。あなたの問題は、この概念を理解していないことに起因していると思います。

プリプロセッサガードがこの問題からコンパイル時に節約しているわけではありません。実際、コンパイル時に、1つのソースファイルのみがobjにコンパイルされ、シンボル定義は解決されません。ただし、リンカがシンボル定義を解決しようとしたときにリンクする場合、複数の定義がエラーのフラグを立てる原因となるのを見て混乱します。

25
Jay

私が過去に使用したことの1つ(グローバル変数が流行していたとき):

var.hファイル:

...
#ifdef DEFINE_GLOBALS
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int global1;
EXTERN int global2;
...

次に、one .cファイル(通常はmain()を含むファイル):

#define DEFINE_GLOBALS
#include "var.h"

残りのソースファイルには、通常「var.h」が含まれています。

DEFINE_GLOBALSはヘッダーガードではなく、定義されているかどうかに応じて変数を宣言/定義できることに注意してください。この手法により、宣言/定義のコピーを1つ作成できます。

26

2つの.cファイルがあります。それらは別々にコンパイルされます。それぞれにヘッダーファイルが含まれています。一度。それぞれが定義を取得します。それらはリンク時に競合します。

従来の解決策は次のとおりです。

#ifdef DEFINE_SOMETHING
int something = 0;
#endif

次に、1つのみ。cファイルでDEFINE_SOMETHINGを#defineします。

10
bmargulies

ヘッダーガードは、ヘッダーファイルが複数回インクルードされるのを防ぎます同じ翻訳単位内(つまり、同じ.cソースファイル内)。ファイルを2つ以上の翻訳単位に含めても、効果はありません。

8
anon