
今つまずいている問題は、VC++2008環境下で、以下のような構造になっているプログラムにおいて、多重定義?されているのでコンパイルが通らないというものです。
ソースコードを載せることは大きすぎてできないので、問題となる部分の記述のみ抽出して書きます。
-------define.h----------
・・・・(module.h内の関数に使われる型の定義など)
---------------------------
-------module.h----------
#include "define.h"
void mod_1(void){・・・}
void mod_2(void){・・・}
---------------------------
このように、2つのヘッダーファイルがあり、define.hをインクルードしてmodule.hを使うという構造です。
(一般的ではないようですが、module.h内にmod_1やmod_2の実体を書き込んでいます。)
その中で、以下のようなcppソースファイルがあります。
-------Main.cpp----------
#include "module.h" (他のMain.cpp内の関数の都合上、Main.cppでもmodule.hをインクルードしています。関係あるかもしれないと思い書きました。)
int main(){
M();
N();
}
------------------------
-------M.cpp----------
#include "module.h"
void M(void){
mod_1();
mod_2();
}
----------------------
-------N.cpp----------
#include "module.h"
void N(void){
mod_1();
mod_2();
}
----------------------
とすると、コンパイルの結果は次のようになります。
1>N.obj : error LNK2005: "void __cdecl mod_1(void)" (?mod_1@@YAXXZ) は既に M.obj で定義されています。
1>N.obj : error LNK2005: "void __cdecl mod_2(void)" (?mod_2@@YAXXZ) は既に M.obj で定義されています。
多重定義や多重インクルードは起こしていないと思っていますが、M.cppとN.cpp内の定義が衝突する理由がわかりません。どなたか理由が思いつく方、教えていただけたら幸いです。お願いいたします!!
◆◆◆ ◆◆◆ ◆◆◆ ◆◆◆ ◆◆◆
ちなみに、たとえばMやNとまったく同じ「A.cpp」を作り、このように書いたとします。
-------A.cpp----------
#include "module.h"
void A(void){
mod_1();
mod_2();
}
----------------------
そしてmain関数の中に、MやNと同様に『A();』を付け加えたとします。
すると、実行結果はこのようになります。
1>M.obj : error LNK2005: "void __cdecl mod_1(void)" (?mod_1@@YAXXZ) は既に A.obj で定義されています。
1>M.obj : error LNK2005: "void __cdecl mod_2(void)" (?mod_2@@YAXXZ) は既に A.obj で定義されています。
1>N.obj : error LNK2005: "void __cdecl mod_1(void)" (?mod_1@@YAXXZ) は既に A.obj で定義されています。
1>N.obj : error LNK2005: "void __cdecl mod_2(void)" (?mod_2@@YAXXZ) は既に A.obj で定義されています。
VC++はファイル名のアルファベット順にコンパイルするようですが、どちらにせよmain関数内で呼び出されていること以外何の関わりも無いはずのA、M、Nの中での出来事が、衝突する理由が、調べども思い当たりません。
お願いいたします。
No.2ベストアンサー
- 回答日時:
インクルードファイルは#include宣言した部分に展開されます。
extern宣言等は単なる外部参照なので重複しても問題はありませんが、ヘッダファイルにソースの実体が書かれている場合は、インクルードしたすべてのソースファイルに同じ関数が展開され、実体が出来ます。
つまり、
#include "module.h"
と書かれているすべてのファイルに
void mod_1(void){・・・}
void mod_2(void){・・・}
が書かれていることと同じなので、リンク時に多重定義でエラーになります。
一般的には「module.h」には
extern void mod_1(void);
extern void mod_2(void);
の外部参照だけを記載し、関数の実体は別のソースファイルに記述します。
No.1さんに引き続き、有難うございました!提示していただいた方法で解決しました!
少しCに詳しくなれました。有難うございます。
No.4
- 回答日時:
良い方法かどうかはわかりませんが一応回避する方法として・・・
module.hに定義しているmod1関数とmod2関数をインラインとして定義する方法があります。
void mod_1(void){・・・}
void mod_2(void){・・・}
これを
inline void mod_1(void){・・・}
inline void mod_2(void){・・・}
こうすると、関数本体が何度出てきても多重定義にはならなくなります。本来は別の目的で使うキーワードですが・・・
有難うございます!
なるほどそんな手が・・・。
Cって本当にややこしいというか、一つの体系としてC全体を捉えるには時間がかかるものですね。
No.1
- 回答日時:
そりゃそうでないの?
module.hに
mod_1();
mod_2();
の実体がある訳でこれをインクルードした
Main.cpp
N.cpp
M.cpp
それぞれに、
mod_1(){・・・}
mod_2(){・・・}
があることになる訳ですね!?
となれば、
Main.obj->mod_1()
N.obj->mod_1()
M.obj->mod_1()
3つのobjをリンクしたら?
同じ部屋に同姓同名のmod_1さんが3人いる訳で…
リンカーさんも、これは困ったぞ! ってことになりませんか?
mod_1()、mod_2() を static にすればエラーにならないと思います
違うかな???
間違ったらごめんね
解決しました!!ヘッダの中身をextern宣言だけにするだけで、いとも簡単に・・・。
しかし、なるほど、です。インクルードの意味、というかC言語のソースの読み方そのものを勘違いしていたようです。有難うございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
1 つ以上の複数回定義されているシンボルが見つかりました
C言語・C++・C#
-
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
C++コンパイル時に『 C1083: include ファイルを開けません。』を表示
C言語・C++・C#
-
-
4
名前空間でビルドエラー(LNK2005)
C言語・C++・C#
-
5
「fatal error C1189」を回避するには?
C言語・C++・C#
-
6
外部依存関係について
C言語・C++・C#
-
7
適切な変換関数が存在しない???
C言語・C++・C#
-
8
外部シンボル ~~"は未解決ですというエラーが直らない"
C言語・C++・C#
-
9
std::stringからLPCWSTR型への変換
C言語・C++・C#
-
10
#include <Windows.h>というヘッダファイルについて
C言語・C++・C#
-
11
CString から LPCTSTRの型に変換
C言語・C++・C#
-
12
Run-Time Check Failure #3というエラーが出ます。
C言語・C++・C#
-
13
スタティックリンクライブラリで2重リンクできる?
C言語・C++・C#
-
14
構文エラー;"が型の前にありませんとは、どうしたら解決できるのですか。"
C言語・C++・C#
-
15
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
16
C++言語で、構造体のコピーは可能(しても良い)のでしょうか?
C言語・C++・C#
-
17
静的でないメンバ関数の呼び出しが正しくありません
C言語・C++・C#
-
18
visual studio でインデントを自動的に揃えるショートカットキー
その他(プログラミング・Web制作)
-
19
画面を強制的に再描画させる方法
C言語・C++・C#
-
20
VC++の外部依存関係
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C# KeyDownイベントでショート...
-
戻り値を返す関数の前に(void)...
-
【gcc・cygwin】multiple defin...
-
const_castのつかいどころを教...
-
既定のコンストラクタがありま...
-
gcc: incompatible pointer type
-
qsortの引数について
-
C++にてtemplateで受け取った任...
-
C#でテンキーの操作は可能でし...
-
静的でないメンバ関数の呼び出...
-
C#でラジオボタンを設定に記録...
-
C言語 プロトタイプ宣言
-
メッセージマップ(ON_CONTROL_...
-
C++ 静的クラスの役割が分からない
-
アドレスを指定して関数を呼び...
-
Delphiの定数とローカル変数の...
-
C++ strlenに関して
-
main関数の戻り値について
-
ウインドウの移動禁止
-
Notepad++の関数リスト表示の変...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
静的でないメンバ関数の呼び出...
-
既定のコンストラクタがありま...
-
C++にてtemplateで受け取った任...
-
多重定義が起きている?--lnk20...
-
【gcc・cygwin】multiple defin...
-
const_castのつかいどころを教...
-
戻り値を返す関数の前に(void)...
-
C言語 ① 5秒間 1秒間隔で点滅を...
-
C# Controls.Addで動的に配置し...
-
C#でテンキーの操作は可能でし...
-
int main()、void main()、void...
-
C# KeyDownイベントでショート...
-
gcc: incompatible pointer type
-
Notepad++の関数リスト表示の変...
-
(void)0 はどんな意味ですか
-
VC++でGetKeyboardStateがうま...
-
関数ポインタについて
-
void main()って誰が最初?:AN...
-
演算子のオーバーロードでコン...
-
この式の意味
おすすめ情報