.hファイルと.cファイルのリンクに問題があります。また、この問題に関するいくつかのスレッドを読みましたが、それらはすべて漠然としていて、まだ概念を完全に理解できていません。リンクに関する多くの問題があります。 、私がbcとbhを持っていると言います、そして私はbhをacとbcの両方に含めるかどうか混乱していますcuz bc自体がbhで定義された構造を知る必要がある、私はいくつかの関数を持っていますそのプロトタイプはbhであり、bcで定義されており、bhの構造も使用します。bcは、bcの関数を使用するacへのインターフェイスに似ているため、bc cuzにbhを含めません。例
b.hファイル
typedef struct{
int x, y;
}myStruct;
void funct1(myStruct);
void funct2(myStruct);
b.cファイル
void funct1(myStruct x)
{
//do something
}
void funct2(myStruct y)
{
//do something
}
a.cファイル
#include "b.h"
int main()
{
myStruct x;
funct1(x);
funct2(y);
return 0;
}
Cygwinでコマンドを実行:gcc b.c a.c -g
混乱する部分ですが、b.cをコンパイルすると、b.hの構造とプロトタイプを検出できないというリンクエラーが発生します。私が知っているすべてのことは、b.hがa.cからb.cをリンクするために使用されることですが、両方の.cがコンパイルされると、b.cがその構造とプロトタイプを見つけることができないようです。
なぜbhをbcに含めなかったのですか?Answer:Cuzは私が知っているとおり、bhはすでにacに含まれており、bcに再び含めたときは、ダブルインクルージョンを行う<---これまでに学んだことであり、#ifdefがあることはわかっていますが、機能しないようです。まだ使い方がわからない場合は、お気軽にご相談ください。この。
どうしたらいいかわからない場合は、遠慮なく教えてください。
#ifdefディレクティブがありますが、これを行う方法がわからないようです。
注:上記のすべてのコードを想定ISスペルが間違っている単語がある場合は、構文的に正しく無視してください。hと.cの間に挿入した後のみです。
確かに#include b.h
でb.c
する必要があります。各ファイルは、リンカーが引き継ぐ前に個別にコンパイルされます。したがって、b.cはそれ自体でコンパイルされ、それを含めない限りb.hの内容を認識しないため、b.hをa.cに含めても問題ありません。
これが#include
ガードの例です
// some_header_file.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// your code
#endif
Some_header_file.hがどこかに含まれている場合、SOME_HEADER_FILE_Hが定義されていると、#ifndef
と#endif
の間のすべてが無視されます。これは、コンパイルユニットに初めて含まれるときに発生します。
プロジェクト内での一意性を確保するために、ファイル名の後に#define
を付けるのが一般的な方法です。他のコードとの衝突のリスクを減らすために、プロジェクトまたは名前空間の名前も前に付けたいと思います。
注:上記のinclude guardを使用しても、同じヘッダーファイルをプロジェクト内に複数回含めることができます。同じコンパイルユニット内に2回含めることはできません。これは次のように示されます。
// header1.h
#ifndef HEADER_H
#define HEADER_H
int test1 = 1;
#endif
// header2.h
#ifndef HEADER_H
#define HEADER_H
int test2 = 2;
#endif
次に、上記の2つのファイルを含めようとするとどうなるかを見てみましょう。単一のコンパイル単位で:
// a.cpp
#include "header1.h"
#include "header2.h"
#include <iostream>
int main()
{
std::cout << test1;
std::cout << test2;
};
Test2が定義されていないため、これはコンパイラエラーを生成します。header2.hでは、HEADER_Hが含まれる時点ですでに定義されているため、これは無視されます。ここで、各ヘッダーを別々のコンパイル単位に含めます。
// a.cpp
#include "header2.h"
int getTest2()
{
return test2;
};
// b.cpp
#include "header1.h"
#include <iostream>
int getTest2(); // forward declaration
int main()
{
std::cout << test1;
std::cout << getTest2();
};
どちらもHEADER_Hを定義する2つのファイルが含まれていますが、正常にコンパイルされ、予期される出力(1および2)が生成されます。
b.h
で定義されている構造を使用するすべてのファイルにb.h
を含める必要があります。したがって、両方のファイルに#include <b.h>
を含める必要があります。 b.h
が数回読み込まれるのを回避するには、ディレクティブ#ifdef
が必要です。あなたの場合:
b.h
#ifndef B_H
#define B_H
typedef struct{
int x, y;
}myStruct;
void funct1(myStruct);
void funct2(myStruct);
#endif
およびb.c:
#include "b.h"
void funct1(myStruct x)
{
//do something
}
void funct2(myStruct y)
{
//do something
}
適切なコーディングでは、b.hをb.cに含めます。
動作するはずのヘッダーガードを次に示します。
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
//header file
#endif
宣言はコメントのある場所に置き、必要なすべての場所に含めます。
編集私が理解している方法では、gcc
は最初にb.cをコンパイルします。これは、a.cがb.cに依存しているためです。しかし、それが最初にb.cをコンパイルするとき、b.h まだ含まれていませんです。
必要がある #include
b.cのb.h。これは単にa.cのインターフェイスではなく、b.cは独自のコードの同じ定義も知っている必要があります。 b.cにb.hを含めない理由は間違っています。各.cファイルは、他のすべての.cファイルとは別にコンパイルされます。コンパイラがa.cで完了すると、b.cで最初からやり直します。 a.cにb.hが含まれていても問題ありません。b.cにはa.cが存在するという概念さえないためです。ヘッダーガードの目的は、特定の.cファイルのコンパイル中に.hファイルが複数回インクルードされた場合に、.hファイルが繰り返し処理されるのを防ぐことです。ガードがないと、宣言が複数回コンパイルされ、既存のシンボルの複数の宣言に関するエラーが発生します。