多重定義が起きている?--lnk2005エラー:VC++

このQ&Aのポイント
  • VC++2008環境下で、複数のヘッダーファイルを使用しているプログラムにおいて、コンパイルエラーが発生しています。
  • ヘッダーファイルとソースファイルの中で同じ関数が定義されているため、LNK2005エラーが発生しています。
  • この問題の解決策としては、ヘッダーファイル内の関数宣言にexternキーワードを追加することで、重複定義エラーを回避することができます。
回答を見る
  • ベストアンサー

多重定義が起きている?--lnk2005エラー:VC++

今つまずいている問題は、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); の外部参照だけを記載し、関数の実体は別のソースファイルに記述します。

emanon_
質問者

お礼

No.1さんに引き続き、有難うございました!提示していただいた方法で解決しました! 少しCに詳しくなれました。有難うございます。

その他の回答 (3)

  • reset_cat
  • ベストアンサー率68% (94/138)
回答No.4

良い方法かどうかはわかりませんが一応回避する方法として・・・ module.hに定義しているmod1関数とmod2関数をインラインとして定義する方法があります。 void mod_1(void){・・・} void mod_2(void){・・・} これを inline void mod_1(void){・・・} inline void mod_2(void){・・・} こうすると、関数本体が何度出てきても多重定義にはならなくなります。本来は別の目的で使うキーワードですが・・・

emanon_
質問者

お礼

有難うございます! なるほどそんな手が・・・。 Cって本当にややこしいというか、一つの体系としてC全体を捉えるには時間がかかるものですね。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.3

>(一般的ではないようですが、module.h内にmod_1やmod_2の実体を書き込んでいます。) やっぱり、ヘッダーファイルに関数の実体を書くのは よくないと思います。

emanon_
質問者

お礼

今回のことで、何故ヘッダーに実体を書くのが一般的でないのかがよくわかりました。以前はLinux上においてgccのゆるゆるコンパイラーだったのでVC++に乗り換えてからは悪戦苦闘です。今回のことで少し、C/C++の書き方を理解できた気がします。

  • joqr
  • ベストアンサー率18% (742/4026)
回答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 にすればエラーにならないと思います 違うかな??? 間違ったらごめんね

emanon_
質問者

お礼

解決しました!!ヘッダの中身をextern宣言だけにするだけで、いとも簡単に・・・。 しかし、なるほど、です。インクルードの意味、というかC言語のソースの読み方そのものを勘違いしていたようです。有難うございました。

関連するQ&A

  • 名前空間でビルドエラー(LNK2005)

    C++の名前空間について勉強しています。 ソースを組んでビルドしようとしたところ、以下のようなエラーが表示されました。 > error LNK2005 "int test::count" は既に main.obj で定義されています。 > fatal error LNK1169: 1つ以上の複数回定義されているシンボルが見つかりました。 変数が多重定義(?)されているというエラーであることはわかるのですが、 その対処法が分からず困っています・・・。 わかる方がいればアドバイスください。 よろしくお願いします。 --------------------------------------- ○main.cpp #include "ns.h" int main(){  test::hoge(); } ○ns.h #pragma once namespace test {  int count;  void hoge(); } ○ns.cpp #include <iostream> #include "ns.h" void test::hoge(){  std::cout << "hoge()が呼ばれた" << test::count++ << "回目" << std::endl; }

  • C++のファイル分割でのエラーについて

    最近VC2008でC++の勉強を始めたのですが、ファイル分割でLNK2005エラーというのが発生し、解消できません。 インクルードガードは行ったのですが、どうしたらよいのか分かりません。 ソースコードはこんな感じです。 //main.cpp #include "sub.h" #include "res.h" bool main(){ calcx(m_x); calcy(m_y); } //res.h 共有変数の宣言 #ifndef __RES_H #define __RES_H int m_x; int m_y; #endif //sub.h 関数のプロトタイプ宣言を行う void calcx(); void calcy(); //sub.cpp 関数の定義を記述する #include "res.h" void calcx(int x){ m_x = x + 100; } void calcy(int y){ m_y = y + 200; } エラー: 1>Main.obj : error LNK2005: "int m_x" (?m_x@@3HA) は既に sub.obj で定義されています。 1>Main.obj : error LNK2005: "int m_y" (?m_y@@3HA) は既に sub.obj で定義されています。 上記のようなエラーを解消するにはどうしたら良いのでしょうか。 何がおかしいのか指摘をお願いします。

  • LNK2005

    Visual C++ Version5.0を使っています。 OSはWindows XPです。 translator.cpp parser.cpp scanner.h という三つのファイルをビルドしようとすると translator.obj : error LNK2005: "int error_flag" (?error_flag@@3HA) は すでに parser.obj で定義されています というエラーがそれぞれの変数ごとに20個出て、最後に ebug/COSC47101.exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました link.exe の実行エラー と表示されます。それらの変数はすべて"scanner.h"で定義されており、 二つの.cppファイルがincludeしているのが原因だということは分かっています。 しかし、どうやって解決すればよいのでしょうか? 過去ログを参考にして二つの.cppファイルの中で #if !defined(HOGE_X) #define HOGE_X #endif //include files #include "scanner.h" とやっても全然駄目です。 どうか解決するまで手取り足取り教えてください。 お願いします。m(__)m

  • vc 2008 C&C++ コンパイル時について

    ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 「1>str_cpy.obj : error LNK2005: _main は既に Cprog.obj で定義されています。 1>str_cpy.obj : error LNK2005: "int __cdecl main(void)" (?main@@$$HYAHXZ) は既に Cprog.obj で定義されています。」 ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー というようなエラーが出た時の対処法はありませんか?これは同プロジェクト内でmainを二回以上使うなということですよね? これじゃ同じプロジェクト内で二つ以上のCファイルは作れないことになりませんか? どなたか解決法があればお願いします。

  • 分割コンパイルの方法がわかりません‥(Studio.NET)

    mainとsubという2つのcppファイルと各ヘッダファイルで分割コンパイルを試みましたがうまくいきません・・。 何が間違っているのでしょう・・。 エラーメッセージ error LNK2005: "char * a" (?a@@3PADA)は既にmain.objで定義されています。 fatal error LNK1169: 1つ以上の複数回定義されているシンボルが見つかりました。 と表示されます。ファイルソースは以下です。どなたか教えてください>< ----------(main.h)---------- char a[100]; ----------(main.cpp)---------- #include<stdio.h> #include "main.h" #include "sub.h" int main(){  sprintf(a,"hello.");  sub_write();  return 0; } -----------(sub.h)----------- void sub_write(); -----------(sub.cpp)------------- #include <stdio.h> #include "main.h" #include "sub.h" void sab(){  printf("%s\n",a); } return; }

  • error LNK2001について

    C++ の勉強中です。 error LNK2001問題がありました。問題点も分からないから、 分かった方に教えていただけないでしょうか? ソースも添付します。環境はVS2005 express edition まず、ヘッダファイルです。ファイル名は、myheader.h #ifndef __MYHEADER_H__ #define __MYHEADER_H__ #define includeshow(x) \ { \ s.show(x); \ } class Sample{ public: void show(char * parameter); }; extern Sample s; #endif //------------------------------------------------ 次に、Sample.cppです。 #include "myheader.h" #include <stdio.h> void Sample::show(char *parameter){ printf("in show func"); } //----------------------------------------------- 最後にTest.cppです。 #include "myheader.h" #include <stdio.h> int main(){ includeshow("ppppp"); } これで error LNK2001: 外部シンボル ""class Sample s" (?s@@3VSample@@A)" は未解決です。というエラーが出ています。 よろしくおねがいします。

  • LNK1120 エラーについて

    このエラーが出たら一体何が問題なんですか? このエラーが出た以降、Visual C++ 2008がずっと使えなくなってしまいました…。ちなみ、この時にビルドで出力されたのは SVCRTD.lib(crtexew.obj) : error LNK2019: 未解決の外部シンボル _WinMain@16 が関数 ___tmainCRTStartup で参照されました。 ■■■\Debug\tr3.exe : fatal error LNK1120: 外部参照 1 が未解決です。 …でした。 あと、入力したものは普通に #include <stdio.h> void main(){ printf ("Hello World"); } です

  • VC++2005ExpressEditionでのエラー

    タイトルの通り、VC++2005EEでプログラムを作成しているのですが ビルド時にエラーが出てしまいます。 ------ ビルド開始: プロジェクト: Object, 構成: Debug Win32 ------ リンクしています... 3jjiki.obj : error LNK2019: 未解決の外部シンボル "int img_R" (?img_R@@3HA) が関数 "void __cdecl JikiLoad(void)" (?JikiLoad@@YAXXZ) で参照されました。 3jjiki.obj : error LNK2019: 未解決の外部シンボル "int img_C" (?img_C@@3HA) が関数 "void __cdecl JikiLoad(void)" (?JikiLoad@@YAXXZ) で参照されました。 3jjiki.obj : error LNK2019: 未解決の外部シンボル "struct BBB * bombig" (?bombig@@3PAUBBB@@A) が関数 "void __cdecl JikiInit(void)" (?JikiInit@@YAXXZ) で参照されました。 3jjiki.obj : error LNK2019: 未解決の外部シンボル "struct BBB * bom" (?bom@@3PAUBBB@@A) が関数 "void __cdecl JikiInit(void)" (?JikiInit@@YAXXZ) で参照されました。 3jjiki.obj : error LNK2019: 未解決の外部シンボル "struct SHOT_C * JitamaC" (?JitamaC@@3PAUSHOT_C@@A) が関数 "void __cdecl JikiShotC(void)" (?JikiShotC@@YAXXZ) で参照されました。 3jjiki.obj : error LNK2019: 未解決の外部シンボル "struct CharaData CharaData" (?CharaData@@3U0@A) が関数 "void __cdecl JikiShotC(void)" (?JikiShotC@@YAXXZ) で参照されました。 3jjiki.obj : error LNK2019: 未解決の外部シンボル "struct SHOT_R * JitamaR" (?JitamaR@@3PAUSHOT_R@@A) が関数 "void __cdecl JikishotR(void)" (?JikishotR@@YAXXZ) で参照されました。 I:\Works\Projects\Object\Debug\Object.exe : fatal error LNK1120: 外部参照 7 が未解決です。 ビルドログは "file://i:\Works\Projects\Object\Object\Debug\BuildLog.htm" に保存されました。 Object - エラー 8、警告 0 ========== ビルド: 0 正常終了、1 失敗、0 更新、0 スキップ ========== 未解決のシンボルと言われているものは全てヘッダーファイルにて extern int img_C; の様に宣言しています。 あれこれ弄って見たのですが全く進展しません。 アドバイスをお願いします。

  • operator new が再定義されています

    自社製のライブラリを使用してPCゲーム開発をしています。 今回、ゲームにネット接続の機能を持たせることとなりました。 ネットゲーム、というほどのものでもなく、 特典のデータがダウンロードできる、といった程度ですが。 コレのためにFTPダウンロードの仕組みを試作しました。 検証用のコンソールアプリケーションではうまくいったのですが、 いざゲームプログラムに組み込んだところ、 nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) は既に (自社製ライブラリ).lib(Allocator.obj) で定義されています。 1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) は既に (自社製ライブラリ)..lib(Allocator.obj) で定義されています。 1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new[](unsigned int)" (??_U@YAPAXI@Z) は既に libcpmtd.lib(newaop.obj) で定義されています。 1>nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete[](void *)" (??_V@YAXPAX@Z) は既に LIBCMTD.lib(delete2.obj) で定義されています。 1>C:\Users\New Challenger\PROGRAMING\(開発中).exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。 というエラーが発生。 「http://support.microsoft.com/kb/148652/ja」 の説明を参考に対処してみたところ、 1>(自社製ライブラリ).lib(Allocator.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) は既に nafxcwd.lib(afxmem.obj) で定義されています。 1>(自社製ライブラリ).lib(Allocator.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) は既に nafxcwd.lib(afxmem.obj) で定義されています。 1>C:\Users\New Challenger\PROGRAMING\(開発中).exe : fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。 となってしまうのですね。 ぶつかり合っている両者のうちの、どちらかがなければエラーを避けられるのは確かなんですが、 自社製ライブラリの方のnew/deleteも、アプリケーションの仕組みに合わせて変形させてあるものなので取っ払ってしまうわけにもいかず、、、 何かうまいこと共存させる方法はないものでしょうか? 自社製のライブラリではありますが、 開発者の方が今現在社を離れているためすぐに回答を得られないので、 広く知恵を貸していただきたいのです。

  • VC++でのリンクエラー [error LNK2005]

    VC++でMFCを使用してダイアログベースのEXEを 作成しています。 以下のクラスのメンバ関数などを使用して、色の操作をしています。 CDC::SetBkColor() CDC::SetTextColor() ビルド時、以下のリンクエラーとなりました。 ---------------------------------------------- nafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) はすでに LIBCMT.lib(delete.obj) で 定義されています Release/MenueTest.exe : fatal error LNK1169: 1 つ 以上の複数回定義されているシンボルが見つかりました link.exe の実行エラー ---------------------------------------------- MFC と C(?)のライブラリで delete()関数が競合しているようですが、これを回避する方法をご存知の方、ご教授願います。 <環境> OS:Windows2000 VC++6.0 <備考> リンクエラーになるのは以下の組み合わせです。 「MFCをスタティックリンクする+リリース版」 MFCをスタティックリンクしてもデバッグ版のビルドだとエラーになりません。 また、MFCをスタティックリンクしない場合もエラーにはなりません。 ただし、リンクエラーにならなかった場合、どちらのオブジェクトの delete()関数が呼ばれるか不明で、それが正しいのかも心配です。

専門家に質問してみよう