web-dev-qa-db-ja.com

コンパイルガードが複数の定義を含めることができないのはなぜですか?

複数の* .cソースファイルに含まれるヘッダーファイルx.hがあります。このヘッダーファイルには、いくつかの構造変数が定義されています。

ヘッダーファイルの先頭に次のように複数の包含防止ガードを配置しました。

#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.


#endif//X_H

ビルド時に、複数の定義に関連するリンカーエラーが発生します。私は問題を理解しています。

  1. 私のようにヘッダーファイルの上部にある複数のインクルード防止ガードは、ヘッダーファイルx.hの複数のインクルードを防ぎ、それによってx.hにある変数の複数の定義を回避しませんか?

  2. #pragma一度この特定のコンパイラでは機能しないので、解決策は何ですか?誰かが投稿した this 同様の質問への回答。うまくいかないようです。このソリューションはどのように機能しますか?

43
goldenmean

リンカーが不平を言っている場合は、ヘッダーの宣言だけでなく定義があることを意味します。これは間違っていることの例です。

#ifndef X_H
#define X_H

int myFunc()
{
  return 42; // Wrong! definition in header.
}

int myVar; // Wrong! definition in header.

#endif

これをソースとヘッダーファイルに次のように分割する必要があります。

ヘッダ:

#ifndef X_H
#define X_H

extern int myFunc();

extern int myVar; 

#endif

Cソース:

int myFunc()
{
  return 42; 
}

int myVar; 
54
Roddy

Includeガードを使用すると、1つのコンパイル単位がヘッダーを2回インクルードすることを防ぎます。例えば。ヘッダーB.hにA.hが含まれ、B.cppにA.hとB.hが含まれる場合、インクルードガードを使用していなければ、A.hからのすべてがコンパイルB.cppで2回宣言されます。

インクルードガードはこれが起こらないようにしますが、今までは問題ありません。

しかし、リンク時に複数の定義を取得します。つまり、2つのコンパイルユニットが同じものを定義します。これは、おそらくヘッダーに実際の定義があり、すべての変数にexternを使用し、関数がインラインであるか、cppファイルで定義されていることを確認します。

13
Pieter

ヘッダーガードは、単一のコンパイルユニット、つまりソースファイルにのみ適しています。ヘッダーファイルを複数回インクルードした場合、おそらくmain.cからインクルードされたすべてのヘッダーにstdio.hがインクルードされている可能性があるため、ガードが役立ちます。

x.hmain.cに含まれるutil.cの関数fの定義がある場合、fmain.cに作成してmain.oを作成し、util.cを作成してutil.oを作成します。次に、リンカは文句を言うでしょう、そしてこれはあなたのヘッダーガードにもかかわらずです。これらのガードのため、#include "x.h"に複数のmain.cステートメントを含めることはもちろん可能です。

12
perreal

関数が大きくない場合は、それらの前に「インライン」を使用でき、リンカは文句を言いません。

7
nclement

複数の包含ガードを使用すると、compilerエラーを回避できますが、リンカーエラーが発生します。ヘッダーファイルにexternを使用しないデータ定義がありますか?

2
Greg Hewgill

多分X_Hはすでにどこかで定義されていますか? Xlibが/usr/include/X11/X.hでX_Hを定義しているこの問題に遭遇しました。

確認するには、gcc -dM -E(gccを使用している場合)を呼び出します。私が使用しているビルドシステムでは、CC=gcc CFLAGS="-dM -E" makeで動作します。ファイルからファイルを削除しても(たとえば#define X_Hを使用して)、出力ファイルにY_Hが含まれている場合は、ソースコードの外部ですでに定義されています。

0
Michael