
今つまずいている問題は、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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# プログラミングペーパーテスト 次の問題の実行結果を答えろ #include int x[ ] = { 1 2022/06/16 21:49
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# プログラミングの授業のペーパーテスト 実行結果を答えろ #include int x[ ] = {1 3 2022/06/16 20:08
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C pointer? or... 2 2022/03/29 00:47
このQ&Aを見た人はこんなQ&Aも見ています
-
1 つ以上の複数回定義されているシンボルが見つかりました
C言語・C++・C#
-
C++コンパイル時に『 C1083: include ファイルを開けません。』を表示
C言語・C++・C#
-
「fatal error C1189」を回避するには?
C言語・C++・C#
-
-
4
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
5
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
6
std::stringからLPCWSTR型への変換
C言語・C++・C#
-
7
外部依存関係について
C言語・C++・C#
-
8
名前空間でビルドエラー(LNK2005)
C言語・C++・C#
-
9
Run-Time Check Failure #3というエラーが出ます。
C言語・C++・C#
-
10
外部シンボル ~~"は未解決ですというエラーが直らない"
C言語・C++・C#
-
11
#include <Windows.h>というヘッダファイルについて
C言語・C++・C#
-
12
静的でないメンバ関数の呼び出しが正しくありません
C言語・C++・C#
-
13
適切な変換関数が存在しない???
C言語・C++・C#
-
14
スタティックリンクライブラリで2重リンクできる?
C言語・C++・C#
-
15
構文エラー;"が型の前にありませんとは、どうしたら解決できるのですか。"
C言語・C++・C#
-
16
エラーの原因は?「この関数の定義が見つかりません」
C言語・C++・C#
-
17
デバッグ中のエラーのことで教えてください。
C言語・C++・C#
-
18
読み込み中にアクセス違反が発生しました、と出ます。これを回避することは
C言語・C++・C#
-
19
visual studio でインデントを自動的に揃えるショートカットキー
その他(プログラミング・Web制作)
-
20
ボタンの表示の色、フォントを変更したい
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C++にてtemplateで受け取った任...
-
既定のコンストラクタがありま...
-
const_castのつかいどころを教...
-
静的でないメンバ関数の呼び出...
-
【gcc・cygwin】multiple defin...
-
多重定義が起きている?--lnk20...
-
gcc: incompatible pointer type
-
C言語 extern について
-
static変数の配列の初期値を空...
-
C# KeyDownイベントでショート...
-
戻り値を返す関数の前に(void)...
-
コールバックって・・・
-
C言語 ① 5秒間 1秒間隔で点滅を...
-
(void)0 はどんな意味ですか
-
4桁7セグでダイナミック点灯
-
PowerShellにてツリービュー入...
-
static constメンバ変数(配列)...
-
関数ポインタについて
-
カノニカルモードの設定について
-
C#でテンキーの操作は可能でし...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
【gcc・cygwin】multiple defin...
-
多重定義が起きている?--lnk20...
-
const_castのつかいどころを教...
-
C++にてtemplateで受け取った任...
-
既定のコンストラクタがありま...
-
戻り値を返す関数の前に(void)...
-
静的でないメンバ関数の呼び出...
-
int main()、void main()、void...
-
C# KeyDownイベントでショート...
-
C# Controls.Addで動的に配置し...
-
(void)0 はどんな意味ですか
-
gcc: incompatible pointer type
-
_beginthreadにて発生するコン...
-
C#でラジオボタンを設定に記録...
-
C#でテンキーの操作は可能でし...
-
C++別のオブジェクトからメンバ...
-
CTabCtrl:TABインデックス単位...
-
見た目は同じソースなのにエラ...
-
pictureboxの画像を削除するには?
-
【VC++6.0】イベントハンドラ関...
おすすめ情報