今つまずいている問題は、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も見ています
-
新NISA制度は今までと何が変わる?非課税枠の拡大や投資対象の変更などを解説!
少額から投資を行う人のための非課税制度であるNISAが、2024年に改正される。おすすめの銘柄や投資額の目安について教えてもらった。
-
1 つ以上の複数回定義されているシンボルが見つかりました
C言語・C++・C#
-
「fatal error C1189」を回避するには?
C言語・C++・C#
-
名前空間でビルドエラー(LNK2005)
C言語・C++・C#
-
-
4
CStringのFindで文字列検索を行いたいのですが
C言語・C++・C#
-
5
既定のコンストラクタがない?
C言語・C++・C#
-
6
画面を強制的に再描画させる方法
C言語・C++・C#
-
7
'const char *' 型は 'char *' 型に変換できない ??
C言語・C++・C#
-
8
#include <Windows.h>というヘッダファイルについて
C言語・C++・C#
-
9
Debug Assertion Failed?
C言語・C++・C#
-
10
CString から LPCTSTRの型に変換
C言語・C++・C#
-
11
GetPrivateProfileStringでiniファイル読込む処理を詳しく知りたいのですが・・・
C言語・C++・C#
-
12
char*を初期化したいのですが
C言語・C++・C#
-
13
charからLPTSTRへの変換方法
C言語・C++・C#
-
14
2重定義って??
C言語・C++・C#
-
15
CStringをwchar_tに変換したい
C言語・C++・C#
-
16
デバッグ中のエラーのことで教えてください。
C言語・C++・C#
-
17
【C++】関数ポインタの使い方
C言語・C++・C#
-
18
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
19
ダイアログ表示時にチェックボックスにチェックされている状態にするには?
C言語・C++・C#
-
20
関数の実体定義にヘッダファイルの2重定義防止方法が効かない?
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
int main()、void main()、void...
-
【gcc・cygwin】multiple defin...
-
Notepad++の関数リスト表示の変...
-
静的でないメンバ関数の呼び出...
-
多重定義が起きている?--lnk20...
-
C# Controls.Addで動的に配置し...
-
ArduinoでMouse関数を使用して...
-
【VC++6.0】イベントハンドラ関...
-
C++にてtemplateで受け取った任...
-
ウインドウの移動禁止
-
_beginthreadにて発生するコン...
-
VC++でGetKeyboardStateがうま...
-
メッセージマップ(ON_CONTROL_...
-
void main()って誰が最初?:AN...
-
critical error c0000005
-
コールバックって・・・
-
gcc: incompatible pointer type
-
const_castのつかいどころを教...
-
SC_SIZEがわからない
-
既定のコンストラクタがありま...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Notepad++の関数リスト表示の変...
-
ArduinoでMouse関数を使用して...
-
【gcc・cygwin】multiple defin...
-
戻り値を返す関数の前に(void)...
-
多重定義が起きている?--lnk20...
-
C++にてtemplateで受け取った任...
-
既定のコンストラクタがありま...
-
静的でないメンバ関数の呼び出...
-
gcc: incompatible pointer type
-
C# Controls.Addで動的に配置し...
-
int main()、void main()、void...
-
(void)0 はどんな意味ですか
-
VC++でGetKeyboardStateがうま...
-
void*型の配列について
-
C# KeyDownイベントでショート...
-
const_castのつかいどころを教...
-
H8マイコンのシリアル通信につ...
-
コールバックって・・・
-
関数ポインタについて
-
void main()って誰が最初?:AN...
おすすめ情報