15

したがって、私が何をしようとも、同じプロジェクト内の複数のソース コード ファイルに同じヘッダー ファイルをインクルードした結果、Dev C++ が多数の複数定義エラーを吐き出すことを避けられないようです。すべてのソース コードを 1 つのファイルにダンプし、ヘッダーを 1 回だけインクルードする必要はありません。ファイルが非常に長くなり、管理が難しくなるためです。

本質的に、これは何が起こっているかです:

#ifndef _myheader_h
#define _myheader_h

typedef struct MYSTRUCT{
int blah;
int blah2; } MYSTRUCT;

MYSTRUCT Job_Grunt;
MYSTRUCT *Grunt = &Job_Grunt;
MYSTRUCT Job_Uruk;
MYSTRUCT *Uruk = &Job_Grunt;

int Other_data[100];

void load_jobs();

#endif

Cpp ファイルの例 (ほとんどすべて次のようになります):

#include "myheader.h"

void load_jobs(){

Grunt->blah = 1;
Grunt->blah2 = 14;

Uruk->blah = 2;
Uruk->blah2 = 15;

return; }

この 1 つのヘッダーを含む約 5 つの cpp ファイルがあり、それぞれがヘッダー ファイルにある異なるタイプの構造体を扱っていることに注意してください。この例では、実際のヘッダー ファイルにはさらに多くのメンバーを持つ約 4 ~ 6 個の異なる構造体があるのに、いくつかのメンバーを含む構造体は 1 つしかありませんでした。これを含めたすべてのファイルは、この例で見られるのと同じ式に従います。

これで、ヘッダー ガードは個々の cpp ファイルがヘッダー ファイルを複数回インクルードするのを防ぐだけであることがわかりました。何が起こっているように見えるかは、コンパイラが各 cpp の開始時にインクルードを読み取るときに、ヘッダー ファイルを最初から定義し直して、次の行と行を吐き出すことです。

Multiple Definition of Uruk, first defined here  
Multiple Definition of Job_Uruk, first defined here  
Multiple Definition of Grunt, first defined here  
Multiple Definition of Job_Grunt, first defined here  
Multiple Definition of Other_data, first defined here

ヘッダーを含むプロジェクト内のほぼすべての cpp ファイルで、このセットが表示されます。構造体と構造体変数の定義をcppファイルに移動しようとしましたが、他のcppファイルはそれらを表示したり操作したりできません。プロジェクト内のすべてのファイルが機能する必要があるため、これは非常に重要ですこれらの構造体で。

しかし、この問題で最も紛らわしい部分については、もう少し説明が必要です。

このプロジェクトでこれらの複数のファイルをセットアップする方法は、私が作業している本、John S. Harbour による All In One Game Programming と同じです。同じプロジェクト内の複数の cpps によって含まれる 1 つのヘッダーを要求する本のサンプル プロジェクトのファイルを作成したときに、まったく同じ問題に遭遇しました。

私はそれらを本から一語一語入力することができました、そして私は一語一語を意味します...
そして私はプロジェクトのすべてのcppについて一連のMDエラーを得るでしょう.

本に付属の CD からサンプル プロジェクトを読み込んだ場合、問題なくコンパイルおよび実行されますが、ファイル自体とプロジェクト オプションは、私が作成したものとまったく同じように見えます。

独自のプロジェクト ファイルを作成し、サンプル プロジェクトのソース ファイルとヘッダー ファイルを CD から追加しただけでも、これもコンパイルおよび実行されますが、それらと私の違いはわかりません。

それで、私は自分のプロジェクト ファイルを作成し、空のソース ファイルとヘッダー ファイルを作成してそれに追加し、対応するはずの CD 上のファイルから内容をコピー アンド ペーストして埋めてみました (同じ働いていたもの)。確かに、私は同じことを得るでしょう...何行ものMDエラーメッセージ。

私は絶対に困惑しています。これらすべての方法を何度も繰り返しましたが、コードの入力ミスやミスコピーではないことを確信しています。事前に作成されたファイル自体に何かがあるようです。いくつかの構成設定または私が完全に欠落している何か...それにより、自分で作成したファイルは正しくコンパイルされませんが、正しくコンパイルされます。

4

9 に答える 9

25

ヘッダー ファイルでこれらの変数を宣言し、各 C++ ファイルにヘッダー ファイルを含めるため、各 C++ ファイルにはそれらの独自のコピーがあります。

これを回避する通常の方法は、ヘッダー ファイル内で変数を宣言しないことです。代わりに、それらを 1 つの C++ ファイルで宣言し、それらをextern必要とする他のすべてのファイルと同様に宣言してください。

私が以前にこれを処理した別の方法は、一部の人々が不快に思うかもしれません...次のように、ヘッダーファイルでそれらを宣言します:

#ifdef MAINFILE
    #define EXTERN
#else
    #define EXTERN extern
#endif

EXTERN MYSTRUCT Job_Grunt;
EXTERN MYSTRUCT *Grunt = &Job_Grunt;
EXTERN MYSTRUCT Job_Uruk;
EXTERN MYSTRUCT *Uruk = &Job_Uruk;

次に、C++ ファイルの1 つに、...

#define MAINFILE

...あなたの#include行の前に。それはすべてを処理し、(私の個人的な意見では) すべてのファイルですべての変数を再宣言するよりもはるかに優れています。

もちろん、本当の解決策はグローバル変数をまったく使用しないことですが、始めたばかりの場合、それを実現するのは困難です。

于 2008-10-21T22:36:05.027 に答える
13

変数を定義すると、コンパイラはその変数用にメモリを確保します。ヘッダー ファイルで変数を定義し、そのファイルをすべてのソース ファイルに含めることで、複数のファイルで同じ変数を定義することになります。

変数定義の前にキーワードを置くと、externこの変数がすでにどこかで定義されており、他のファイルが使用できるように変数を宣言(つまり名前付け) しているだけであることをコンパイラに伝えます。

したがって、ヘッダー ファイルでは、キーワードを追加して、すべての定義を前方宣言にする必要があります。extern

extern MYSTRUCT Job_Grunt;
extern MYSTRUCT *Grunt;
extern MYSTRUCT Job_Uruk;
extern MYSTRUCT *Uruk;

extern int Other_data[100];

次に、ソース ファイルの 1(1 つだけ) で、変数を通常どおりに定義します。

MYSTRUCT Job_Grunt;
MYSTRUCT *Grunt = &Job_Grunt;
MYSTRUCT Job_Uruk;
MYSTRUCT *Uruk = &Job_Grunt;

int Other_data[100];
于 2008-10-21T22:41:13.440 に答える
6

複数の定義が表示されている理由については、他のほとんどの回答が正しいですが、用語は不正確です。宣言と定義を理解することが問題の鍵です。

宣言はアイテムの存在を通知しますが、インスタンス化は行いません。したがって、extern ステートメントは宣言であり、定義ではありません。

定義は、定義された項目のインスタンスを作成します。したがって、ヘッダーに定義がある場合、各 .cpp ファイルでインスタンス化され、複数の定義が生成されます。定義は宣言でもあります。たとえば、アイテムのスコープが 1 つの .cpp ファイルに限定されている場合、個別の宣言は必要ありません。

注: ここでのインスタンス化という言葉の使用は、実際にはデータ項目にのみ適用されます。

于 2008-10-22T01:21:37.830 に答える
5

ヘッダー ファイルで変数を extern として定義してから、それらを cpp ファイルでも定義する必要があります。すなわち:

extern MYSTRUCT Job_Grunt;

ヘッダー ファイルで、次にプロジェクトの cpp ファイルで通常どおり宣言します。

ヘッダー ファイルは定義専用です。ヘッダー ファイルで変数をインスタンス化すると、ヘッダーがプロジェクトに含まれるたびにインスタンス化が試行されます。extern ディレクティブを使用すると、それが単なる定義であり、インスタンス化が別の場所で行われることがコンパイラに伝えられます。

于 2008-10-21T22:32:03.350 に答える
2

.h ファイルで定義された関数に対してもこのエラーを受け取りました。ヘッダー ファイルは、クラスの宣言を行うことを意図したものではなく、プロジェクトのさまざまな場所で必要とされるいくつかの関数の定義を行うことを目的としていました。(「定義」と「宣言」の使用法を混同するかもしれませんが、主なアイデアを与えることができれば幸いです。)「複数の定義」エラーを与える関数の定義の直前に「インライン」キーワードを置くと、エラーが回避されます。

于 2011-06-07T09:09:21.483 に答える
0

私もしばらく前にこの問題を抱えていました。何が解決したのか説明してみましょう。すべての宣言があり、すべての cpp ファイルに含める必要がある global.h ファイルがありました。すべての .cpp に含める代わりに、.h に含めました。すべての ".h" ファイルに #ifndef と #define の行を追加し、#endif で終了しました。これでMDの問題が解決しました。これがあなたにとってもうまくいくことを願っています。

于 2009-04-19T07:36:42.360 に答える
0

ジェラルドが言ったことを拡張するために、ヘッダーは構造体のインスタンスを定義しています(これはあなたが望むものではありません)。これにより、ヘッダーを含む各コンパイル ユニット (cpp ファイル) が構造体インスタンスの独自のバージョンを取得し、リンク時に問題が発生します。

Gerald が言ったように、ヘッダーで (「extern」を使用して) 構造体への参照を定義し、インスタンスをインスタンス化するプロジェクトに 1 つの cpp ファイルを用意する必要があります。

于 2008-10-21T22:36:45.057 に答える
-3

GCC 3.4 以降は#pragma once. #pragma onceインクルード ガードを使用する代わりに、コードの先頭に置くだけです。これはより成功するかもしれないし、そうでないかもしれませんが、試してみる価値はあります。いいえ、これは(常に)インクルードガードと正確に同等ではありません。

于 2008-10-21T22:41:36.590 に答える