




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、already defined in *.obj“符號(hào)已定義”問(wèn)題原理及解決方案C+Base 2010-06-15 15:08:25 閱讀103 評(píng)論0 字號(hào):大中小 訂閱 造成LNK2005錯(cuò)誤主要有以下幾種情況: 1重復(fù)定義全局變量。可能存在兩種情況: A、對(duì)于一些初學(xué)編程的程序員,有時(shí)候會(huì)以為需要使用全局變量的地方就可以使用定義申明一下。其實(shí)這是錯(cuò)誤的,全局變量是針對(duì)整個(gè)工程的。正確的應(yīng)該是在一個(gè)CPP文件中定義如下:int g_Test;那么在使用的CPP文件中就應(yīng)該使用:extern int g_Test即可,如果還是使用int g_Test,那么就
2、會(huì)產(chǎn)生LNK2005錯(cuò)誤,一般錯(cuò)誤錯(cuò)誤信息類似:AAA.obj error LNK2005 int book c?book3HA already defined in BBB.obj。切記的就是不能給變量賦值否則還是會(huì)有LNK2005錯(cuò)誤。 這里需要的是“聲明”,不是“定義”!根據(jù)C+標(biāo)準(zhǔn)的規(guī)定,一個(gè)變量是聲明,必須同時(shí)滿足兩個(gè)條件,否則就是定義: (1)聲明必須使用extern關(guān)鍵字;(2)不能給變量賦初值 所以,下面的是聲明: extern in
3、t a; 下面的是定義 int a; int a = 0; extern int a =0; B、對(duì)于那么編程不是那么嚴(yán)謹(jǐn)?shù)某绦騿T,總是在需要使用變量的文件中隨意定義一個(gè)全局變量,并且對(duì)于變量名也不予考慮,這也往往容易造成變量名重復(fù),而造成LNK2005錯(cuò)誤。 2頭文件的包含重復(fù)。往往需要包含的頭文件中含有變量、函數(shù)、類的定義,在其它使用的地方又不得不多次包含之,如果頭文件中沒有相關(guān)的宏等防止重復(fù)鏈接的措施,那么就會(huì)產(chǎn)生LNK2005錯(cuò)誤。解決辦法是在需要包含的頭文件中做類似的處理:#ifndef MY_H_FILE /如果沒有定義這
4、個(gè)宏 #define MY_H_FILE /定義這個(gè)宏 . /頭文件主體內(nèi)容 . #endif 上面是使用宏來(lái)做的,也可以使用預(yù)編譯來(lái)做,在頭文件中加入: #pragma once /頭文件主體 3使用第三方的庫(kù)造成的。這種情況主要是C運(yùn)行期函數(shù)庫(kù)和MFC的庫(kù)沖突造成的。具體的辦法就是將那個(gè)提示出錯(cuò)的庫(kù)放到另外一個(gè)庫(kù)的前面。另外選擇不同的C函數(shù)庫(kù),可能會(huì)引起這個(gè)錯(cuò)誤。微軟和C有兩種C運(yùn)行期函數(shù)庫(kù),一種是普通的函數(shù)庫(kù):LIBC.LIB,不支持多線程。另外一種是支持多線程的:ms
5、vcrt.lib。如果一個(gè)工程里,這兩種函數(shù)庫(kù)混合使用,可能會(huì)引起這個(gè)錯(cuò)誤,一般情況下它需要MFC的庫(kù)先于C運(yùn)行期函數(shù)庫(kù)被鏈接,因此建議使用支持多線程的msvcrt.lib。所以在使用第三方的庫(kù)之前首先要知道它鏈接的是什么庫(kù),否則就可能造成LNK2005錯(cuò)誤。如果不得不使用第三方的庫(kù),可以嘗試按下面所說(shuō)的方法修改,但不能保證一定能解決問(wèn)題,前兩種方法是微軟提供的: A、選擇VC菜單Project->Settings->Link->Catagory選擇Input,再在Ignore libraries 的Edit欄中填入你需要忽略的庫(kù),如:Nafxcwd.lib;Libcmtd.
6、lib。然后在Object/library Modules的Edit欄中填入正確的庫(kù)的順序,這里需要你能確定什么是正確的順序,呵呵,God bless you! B、選擇VC菜單Project->Settings->Link頁(yè),然后在Project Options的Edit欄中輸入/verbose:lib,這樣就可以在編譯鏈接程序過(guò)程中在輸出窗口看到鏈接的順序了。 C、選擇VC菜單Project->Settings->C/C+頁(yè),Catagory選擇Code Generation后再在User Runtime libraray中選擇MultiThread DLL等其他庫(kù)
7、,逐一嘗試。 關(guān)于編譯器的相關(guān)處理過(guò)程,參考: 這就是我所遇到過(guò)的LNK2005錯(cuò)誤的幾種情況,肯定還有其他的情況也可能造成這種錯(cuò)誤,所以我不希望你在看完這篇文章以后,再遇到LNK2005錯(cuò)誤時(shí)候,不動(dòng)腦筋的想對(duì)號(hào)入座的排除錯(cuò)誤。編程的過(guò)程就是一個(gè)思考的過(guò)程,所以還是多多開動(dòng)你的頭腦,那樣收獲會(huì)更多! 附錄:編譯器處理相關(guān) 一.預(yù)處理器-編譯器-匯編器-鏈接器預(yù)處理器會(huì)處理相關(guān)的預(yù)處理指令,一般是以"#"開頭的指令。如:#include "xx.h" #define等。編譯器把對(duì)應(yīng)的*.cpp翻譯成*.s文件(匯編語(yǔ)言)。匯編器則處理*.s生成對(duì)應(yīng)的*.
8、o文件(obj目標(biāo)文件)最后鏈接器把所有的*.o文件鏈接成一個(gè)可執(zhí)行文件(?.exe)1.部件:首先要知道部件(可以暫且狹義地理解為一個(gè)類)一般分為頭文件(我喜歡稱為接口,如:*.h)及實(shí)現(xiàn)文件(如:*.cpp)。一般頭文件會(huì)是放一些用來(lái)作聲明的東東作為接口而存在的。而實(shí)現(xiàn)文件主要是實(shí)現(xiàn)的具體代碼。2.編譯單個(gè)文件:記住IDE在bulid文件時(shí)只編譯實(shí)現(xiàn)文件(如*.cpp)來(lái)產(chǎn)生obj,在vc下你可以對(duì)某個(gè)?.cpp按下ctrl+f7單獨(dú)編譯它生成對(duì)應(yīng)一個(gè)?.obj文件。在編譯?.cpp時(shí)IDE會(huì)在?.cpp中按順序處理用#include包括進(jìn)來(lái)的頭文件(如果該頭文件中又#include有文件
9、,同樣會(huì)按順序跟進(jìn)處理各個(gè)頭文件,如此遞歸。)3.內(nèi)部鏈接與外部鏈接:內(nèi)、外鏈接是比較基礎(chǔ)的東東,但是也是新手最容易錯(cuò)的地方,所以這里有必要祥細(xì)討論一下。內(nèi)部鏈接產(chǎn)生的符號(hào)只在本地?.obj中可見,而外部鏈接的符號(hào)是所有*.obj之間可見的。如:用inline的是內(nèi)部鏈接,在文件頭中直接聲明的變量、不帶inline的全局函數(shù)都是外部鏈接。在文件頭中類的內(nèi)部聲明的函數(shù)(不帶函數(shù)體)是外部鏈接,而帶函數(shù)體一般會(huì)是內(nèi)部鏈接(因?yàn)镮DE會(huì)盡量把它作為內(nèi)聯(lián)函數(shù))認(rèn)識(shí)內(nèi)部鏈接與外部鏈接有什么作用呢?下面用vc6舉個(gè)例子:/ 文件main.cpp內(nèi)容:void main()/ 文件t1.cpp內(nèi)容:#inc
10、lude "a.h"void Test1() Foo(); / 文件t2.cpp內(nèi)容:#include "a.h"void Test2() Foo(); / 文件a.h內(nèi)容:void Foo( ) 好,用vc生成一個(gè)空的console程序(File - new - projects - win32 console application),并關(guān)掉預(yù)編譯選項(xiàng)開關(guān)(project - setting - Cagegoryrecompiled Headers - Not using precompiled headers)現(xiàn)在你打開t1.cpp按ctrl+f7
11、編譯生成t1.obj通過(guò)打開t2.cpp按ctrl+f7編譯生成t2.obj通過(guò)而當(dāng)你鏈接時(shí)會(huì)發(fā)現(xiàn):Linking.t2.obj : error LNK2005: "void _cdecl Foo(void)" (?FooYAXXZ) already defined in t1.obj這是因?yàn)?1. 編譯t1.cpp在處理到#include "a.h"中的Foo時(shí)看到的Foo函數(shù)原型定義是外部鏈接的,所以在t1.obj中記錄Foo符號(hào)是外部的。2. 編譯t2.cpp在處理到#include "a.h"中的Foo時(shí)看到的Foo函數(shù)原型定
12、義是外部鏈接的,所以在t2.obj中記錄Foo符號(hào)是外部的。3. 最后在鏈接 t1.obj 及 t2.obj 時(shí), vc發(fā)現(xiàn)有兩處地方(t1.obj和t2.obj中)定義了相同的外部符號(hào)(注意:是定義,外部符號(hào)可以多處聲明但不可多處定義,因?yàn)橥獠糠?hào)是全局可見的,假設(shè)這時(shí)有t3.cpp聲明用到了這個(gè)符號(hào)就不知道應(yīng)該調(diào)用t1.obj中的還是t2.obj中的了),所以會(huì)報(bào)錯(cuò)。解決的辦法有幾種: a.將a.h中的定義改寫為聲明,而用另一個(gè)文件a.cpp來(lái)存放函數(shù)體。(提示:把上述程序改來(lái)試試)(函數(shù)體放在其它任何一個(gè)cpp中如t1.cpp也可以,不過(guò)良好的習(xí)慣是用對(duì)應(yīng)cpp文件來(lái)存放)。這時(shí)包括a.
13、h的文件除了a.obj中有函數(shù)體代碼外,其它包括a.h的cpp生成的obj文件都只有對(duì)應(yīng)的符號(hào)而沒有函數(shù)體,如t1.obj、t2.obj就只有符號(hào),當(dāng)最后鏈接時(shí)IDE會(huì)把a(bǔ).obj的Foo()函數(shù)體鏈接進(jìn)exe文件中,并把t1.obj、t2.obj中的Foo符號(hào)轉(zhuǎn)換成對(duì)應(yīng)在函數(shù)體exe文件中的地址。另外:當(dāng)變量放在a.h中會(huì)變成全局變量的定義,如何讓它變?yōu)槁暶髂?例如: 我們?cè)赼.h中加入:class CFoo;CFoo* obj;這時(shí)按f7進(jìn)行build時(shí)出現(xiàn):Linking.t2.obj : error LNK2005: "class CFoo * obj" (?obj
14、3PAVCFooA) already defined in t1.obj一個(gè)好辦法就是在a.cpp中定義此變量( CFoo* obj,然后拷貝此定義到a.h文件中并在前面加上extern(extern CFoo* obj如此就可通過(guò)了。當(dāng)然extern也可以在任何調(diào)用此變量的位置之前聲明,不過(guò)強(qiáng)烈建議不要這么作,因?yàn)榈教幾饔胑xtern,會(huì)導(dǎo)致接口不統(tǒng)一。良好的習(xí)慣是接口一般就放到對(duì)應(yīng)的頭文件。b. 將a.h中的定義修改成內(nèi)部鏈接,即加上inline關(guān)鍵字,這時(shí)每個(gè)t1.obj和t2.obj都存放有一份Foo函數(shù)體,但它們不是外部符號(hào),所以不會(huì)被別的obj文件引用到,故不存在沖突。(提示:把上
15、述程序改來(lái)試試)另外我作了個(gè)實(shí)驗(yàn)來(lái)驗(yàn)證”vc是把是否是外部符號(hào)的標(biāo)志記錄在obj文件中的“(有點(diǎn)繞口)??梢钥纯矗缦?(1)文件內(nèi)容:/ 文件main.cpp內(nèi)容:void main()/ 文件t1.cpp內(nèi)容:#include "a.h"void Test1() Foo(); / 文件t2.cpp內(nèi)容:#include "a.h"void Test2() Foo(); / 文件a.h內(nèi)容:inline void Foo( ) (2) 選t1.cpp按ctrl+f7單獨(dú)編譯,并把編譯后的t1.obj修改成t1.obj_inline(3) 選t2.cpp
16、按ctrl+f7單獨(dú)編譯,并把編譯后的t2.obj修改成t2.obj_inline(4) 把除了t1.obj_inline及t2.obj_inline外的其它編譯生成的文件刪除。(5) 修改a.h內(nèi)容為:void Foo( ) ,使之變?yōu)榉莾?nèi)聯(lián)函數(shù)作測(cè)試(6) rebuild all所有文件。這時(shí)提示:Linking.t2.obj : error LNK2005: "void _cdecl Foo(void)" (?FooYAXXZ) already defined in t1.objDebug/cle.exe : fatal error LNK1169: one or m
17、ore multiply defined symbols found(7) 好,看看工程目錄下的debug目錄中會(huì)看到新生成的obj文件。下面我們來(lái)手工鏈接看看,打開菜單中的project - setting - Link,拷貝Project options下的所有內(nèi)容,如下:kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.
18、lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/cle.pdb" /debug /machine:I386 /out:"Debug/cle.exe" /pdbtype:sept 把它修改成:Link.exe kernel32.lib user32.lib
19、 gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:y
20、es /pdb:"Debug/cle.pdb" /debug /machine:I386 /out:"Debug/cle.exe" /pdbtype:sept Debug/t1.obj Debug/t2.obj Debug/main.objpause注意前面多了Link.exe,后面多了Debug/t1.obj Debug/t2.obj Debug/main.obj以及最后一個(gè)pause批處理命令,然后把它另存到工程目錄(此目錄下會(huì)看到debug目錄)下起名為link.bat運(yùn)行它,就會(huì)看到:t2.obj : error LNK2005: "v
21、oid _cdecl Foo(void)" (?FooYAXXZ) already defined in t1.objDebug/cle.exe : fatal error LNK1169: one or more multiply defined symbols found很好,我們鏈接原來(lái)的obj文件得到的效果跟在vc中用rebuild all出來(lái)的效果一樣。那么現(xiàn)在如果我們把備份出來(lái)的t1.obj_inline覆蓋t1.obj而t2.obj_inline覆蓋t2.obj再手動(dòng)鏈接應(yīng)該會(huì)是不會(huì)出錯(cuò)的,因?yàn)樵璽1.obj_inline及t2.obj_inline中存放的是內(nèi)部鏈接符
22、號(hào)。好運(yùn)行Link.bat,果然不出所料,鏈接成功了,看看debug目錄下多出了一個(gè)exe文件。這就說(shuō)明了內(nèi)或外符號(hào)在obj有標(biāo)志標(biāo)識(shí)!(提示:上述為什么不用vc的f7build鏈接呢,因?yàn)槲募r(shí)間改變了,build會(huì)重新生成新的obj,所以我們用手動(dòng)鏈接保證obj不變)注bj信息可用dumpbin.exe查看4.#include規(guī)則:有很多人不知道#include 文件該放在何處?1). 增強(qiáng)部件自身的完整性:為了保證部件完整,部件的cpp實(shí)現(xiàn)文件(如test.cpp)中第一個(gè)#include的應(yīng)當(dāng)是它自身對(duì)應(yīng)的頭文件(如test.h)。(除非你用預(yù)編譯頭文件, 預(yù)編譯頭必須放在第一個(gè))。這
23、樣就保證了該部件頭文件(test.h)所必須依賴的其它接口(如a.h等)要放到它對(duì)應(yīng)的文件頭中(test.h),而不是在cpp中(test.cpp)把所依賴的其它頭文件(a.h等)移到其自身對(duì)應(yīng)的頭文件(test.h等)之前(因?yàn)檫@樣強(qiáng)迫其它包括此部件的頭文件(test.h)的文件(b.cpp)也必須再寫一遍include(即b.cpp若要#include "test.h"也必須#include "a.h")”。另外我們一般會(huì)盡量減少文件頭之間的依賴關(guān)系,看下面:2). 減少部件之間的依賴性:在1的基礎(chǔ)上盡量把#include到的文件放在cpp中包括。這就要求我們一般不要在頭文件中直接引用其它變量的實(shí)現(xiàn),而是把此引用搬到實(shí)現(xiàn)文件中。例如: / 文件foo.h:class CFoovoid Foo();/ 文件test.h:#include "foo.h"class CTestCFoo* m_pFoo;public:CTest() : m_pFoo(NULL)void Test() if(m_pFoo) m_pFoo->Foo();.;/ 文件test.cpp:#include "test.h".如上文件test.h中我們其實(shí)可以#include
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年寧夏青吳忠市銅峽高級(jí)中學(xué)物理高一第二學(xué)期期末檢測(cè)試題含解析
- 網(wǎng)絡(luò)學(xué)術(shù)交流中的身份認(rèn)同策略分析
- 睡眠障礙的治療及護(hù)理
- 《詭才之道》:類型電影探索新視角下的顛覆與創(chuàng)新
- 腦水腫的健康宣教2-
- 縱隔炎性假瘤個(gè)案護(hù)理
- 顴骨結(jié)核的治療及護(hù)理
- 異位葡萄胎的健康宣教
- 人格障礙的護(hù)理查房
- 眼眶畸形的護(hù)理查房
- 《輔行訣五臟用藥法要》解讀
- 領(lǐng)導(dǎo)干部報(bào)告?zhèn)€人有關(guān)事項(xiàng)檢討14篇
- 計(jì)算機(jī)組成原理(本全)白中英課件
- 2023中國(guó)專利獎(jiǎng)申報(bào)實(shí)務(wù)
- 常見骨關(guān)節(jié)疾病的評(píng)定技術(shù)-肩關(guān)節(jié)周圍炎的評(píng)定技術(shù)(康復(fù)評(píng)定技術(shù)課件)
- 益海嘉里(盤錦)糧油工業(yè)有限公司稻殼鍋爐可研報(bào)告
- JGJ106-2014 建筑基樁檢測(cè)技術(shù)規(guī)范
- 醫(yī)務(wù)科崗前培訓(xùn)
- 共青團(tuán)團(tuán)課主題班會(huì)課件PPT模板PPT
- GB/T 8685-2008紡織品維護(hù)標(biāo)簽規(guī)范符號(hào)法
- 合成氨行業(yè)發(fā)展現(xiàn)狀及趨勢(shì)分析
評(píng)論
0/150
提交評(píng)論