#ifndef
インクルード ガードは、翻訳単位 (通常は単一のソース ファイル) のレベルでのみ機能します。
2 つの翻訳単位で同じオブジェクトを 2 回定義すると、インクルード ガードでは修正されませんが、2 つのオブジェクト ファイルを 1 つの実行可能ファイルに結合しようとすると、リンカは激しく文句を言います。
あなたの状況は次のようなものだと思います:
hdr.h:
#ifndef HDR_H
#define HDR_H
void rc(void);
int xyzzy;
#endif
prog1.c:
#include "hdr.h"
#include "hdr.h"
int main (void) { rc(); return xyzzy; }
prog2.c:
#include "hdr.h"
void rc(void) { xyzzy = 0; }
そのような状況では、インクルード ガードはヘッダーが に 2 回インクルードされるのを防ぎますが、とprog1.c
の両方にインクルードされます。つまり、それぞれに のコピーが含まれます。prog1.c
prog2.c
xyzzy
それらを一緒にリンクすると、リンカーはそれを好まないでしょう。
解決策は、ヘッダーで何かを定義するのではなく、ヘッダーで宣言するだけで、C ファイルの定義を残すことです。
hdr.h:
#ifndef HDR_H
#define HDR_H
int rc(void);
extern int xyzzy; // declare, not define
#endif
prog1.c:
#include "hdr.h"
#include "hdr.h"
int main (void) { rc(); return xyzzy; }
prog2.c:
#include "hdr.h"
int xyzzy; // define
int rc(void) { xyzzy = 0; }
宣言とは、関数プロトタイプ、extern 変数、typedef などのようなものです (簡単に言うと、実際に「オブジェクト」を作成せずに何かが存在することを宣言するものです)。
定義とは、非 extern 変数などの「オブジェクト」を作成するものです。
どの「オブジェクト」が 2 回定義されているかを追跡する必要があります (リンカーの出力には のようなものがあるはずです)。次に、それがヘッダーで定義さdoubly-defined symbol 'xyzzy'
れていないことを確認します。