error LNK2005 が回避出来ません – プログラミング – Home

error LNK2005 が回避出来...
 
通知
すべてクリア

[解決済] error LNK2005 が回避出来ません


Kon
 Kon
(@Kon)
ゲスト
結合: 19年前
投稿: 89
Topic starter  

お久しぶりです。Konです。
またお力をお借りしたく、よろしくお願い致します。

PCはWinXP、MicrosoftVisualC++6.0 を使用しています。
MFC で、基本クラスをCFormView にしてプロジェクトを作りました。

プロジェクト全体で使用したい下記のような、構造体があります。
struct INDEXSET{
int xx;
int yy;
} StrIndex[DATABUF_NUM];

二重定義を回避するため、#ifndef を使いました。

//---AAAView.h------------------------
D#define NUM 100

#ifndef _AAAView_H_
#define _AAAView_H_
struct INDEXSET{
int xx;
int yy;
} StrIndex[NUM];
#else
extern struct INDEXSET{
int xx;
int yy;
}StrIndex[NUM];
#endif

//---AAAView.cpp------------
#include AAAView.h
//---BBB.cpp----------------
#include AAAView.h

この状態でコンパイルすると
InterFaceView.obj : error LNK2005: struct INDEXSET * StrIndex (?
StrIndex@@3PAUINDEXSET@@A) はすでに InterFace.obj で定義されています。
とエラーになり解決できずに困っています。
何が問題なのか、おわかりになりませんか?


引用未解決
トピックタグ
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

>#else
>extern struct INDEXSET{
> int xx;
> int yy;
>}StrIndex[NUM];
>#endif
で、またstructを定義しているからではないでしょうか?

単に

#else
extern struct INDEXSET StrIndex[NUM];
#endif

とするとどうでしょうか?


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

原因は、AAAView.cppからでもBBB.cppからでも、
#elseより前の部分が展開されるから。
なぜならば、それぞれのソースコードで、インクルード文を
展開する時点では、_AAAView_H_が定義されてなかったから。

正しく書くには、

//---AAAView.h------------------------
#define NUM 100

#ifndef _AAAView_H_
#define _AAAView_H_
struct INDEXSET{
int xx;
int yy;
};
extern INDEXSET StrIndex[NUM];
#endif

//---AAAView.cpp------------
#include AAAView.h
INDEXSET StrIndex[NUM]; // <- BBB.cppにだけ書くのも可
//---BBB.cpp----------------
#include AAAView.h


返信引用
Kon
 Kon
(@Kon)
ゲスト
結合: 19年前
投稿: 89
Topic starter  

Blueさん、たいちうさん、早速のご回答ありがとうございました。

Blueさん
>単に
>#else
>extern struct INDEXSET StrIndex[NUM];
>#endif
>とするとどうでしょうか?
としても、おなじエラーになりました。

たいちうさんの方法でしたら、エラーは出なくなりました。

これは、ヘッダーファイルのインクルードが
AAAView.cpp と BBB.cpp で同時に進行してしまうからなのでしょうか?
また、
>INDEXSET StrIndex[NUM]; // <- BBB.cppにだけ書くのも可
この、どちらか片方に書けばよいというコトが、
すんなり理解できないのですが・・・???


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

extern INDEXSET StrIndex[NUM]; の意味は「どこかに StrIndex という配列が有る」
つまり、
別のファイルかもしれないし、同一ファイル内かもしれないけれども、
どこかにあるのでそういう名前を以下で使えるようにする、ということ
// 名前を使えるようにする=宣言

extern を伴わずに INDEXSET StrIndex[NUM]; と書くと、これの意味は
「ここで StrIndex という配列を作る」
ここで作るので、もちろんその名前は以下で使えるようになる
// 名前だけでなく実体を作る=定義

AAAView.cpp でも BBB.cpp でも配列実体を作ってしまうと C2005
実体は1個でなければならない、という規則があるため。

んで、この StrIndex は View の持ち物なのかな?
そうであれば現状でよし、
そうでないなら StrIndex.cpp と StrIndex.h を用意するほうが良い。


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

> これは、ヘッダーファイルのインクルードが
> AAAView.cpp と BBB.cpp で同時に進行してしまうからなのでしょうか?

コンパイルの単位はソースファイルなので、別のソースファイルに
何がインクルードされているかは関係ない。

> >INDEXSET StrIndex[NUM]; // <- BBB.cppにだけ書くのも可
> この、どちらか片方に書けばよいというコトが、
> すんなり理解できないのですが・・・???

AAAView.cppとBBB.cppの両方でStrIndexを使いたいならば、
ソースファイルをコンパイルする時に、StrIndexの宣言を参照できれば良い。
extern INDEXSET StrIndex[NUM]; がそれ。
実態があっても無くてもコンパイルはできる。

ここまでが、コンパイルの話。実行ファイルの断片を作っている。

次に断片やコンパイラが用意している標準関数のライブラリなどをくっ付けて、
実行ファイルを作る(リンク)。

このときに、externのないINDEXSET StrIndex[NUM]; が、1つもなかったり、
複数のソースコードにあったら、リンクエラー。

この話は、#ifndefを使った二重インクルード防止とは関係のない話。
二重インクルード防止は、1つのソースファイルに同じヘッダーファイルを
複数回インクルードするのを防止するための手段。


返信引用
Kon
 Kon
(@Kon)
ゲスト
結合: 19年前
投稿: 89
Topic starter  

tetrapodさん、たいちうさん、ありがとうございました。
やはり、参考書読むより、教えて頂いた方が、理解が早いですね。
助かりました。本当にありがとうございます。

StrIndex は View の持ち物です。
今後、Viewの子ウインドウを作る予定で、
その準備として定義をAAAView.cppからAAAView.hに移植したところ
BBB.cppもAAAView.hを呼んでいてエラーになった。という経緯です。

StrIndex.cpp と StrIndex.h を用意するメリットは、
他のソースから、アクセスしやすいからという理解で良いのでしょうか?
子ウインドウは、多数になる予感がしていますので、
なるべくシンプルにわかりやすく管理したいのです。
(話題が変りそうなので、別スレッドにした方が良いですか?)

コンパイルエラーとリンクエラーの違いがいまいちピンと来なかったのですが
たいちうさんの説明でよく分かりました。


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

> StrIndex.cpp と StrIndex.h を用意するメリットは、
> 他のソースから、アクセスしやすいからという理解で良いのでしょうか?
> 子ウインドウは、多数になる予感がしていますので、
> なるべくシンプルにわかりやすく管理したいのです。
> (話題が変りそうなので、別スレッドにした方が良いですか?)

メリットは、モジュール性が高まることでしょう。
Viewとか、Docとかの他のモジュールとは別の独立したモジュールならば、
AAAView.hやAAAView.cppに間借りするよりも、別のファイルにしたほうが良い。

ですがViewの持ち物ということなので、ファイルを分ける必要はないでしょう。
むしろ、Viewクラスのメンバ変数にすることを検討するべきかと。

>(話題が変りそうなので、別スレッドにした方が良いですか?)

違う話題は、別スレッドが原則です。
長くなりそうなら分けてください。


返信引用
Kon
 Kon
(@Kon)
ゲスト
結合: 19年前
投稿: 89
Topic starter  

たいちうさんありがとうございました。
確かに、Viewクラスのメンバ変数にした方が良さそうですね。

当初の目的はクリアしましたので、
ここで解決に致します。
皆様、ありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました