收藏 分享(赏)

重命名处理.doc

上传人:hskm5268 文档编号:8930695 上传时间:2019-07-17 格式:DOC 页数:10 大小:40.50KB
下载 相关 举报
重命名处理.doc_第1页
第1页 / 共10页
重命名处理.doc_第2页
第2页 / 共10页
重命名处理.doc_第3页
第3页 / 共10页
重命名处理.doc_第4页
第4页 / 共10页
重命名处理.doc_第5页
第5页 / 共10页
点击查看更多>>
资源描述

1、造成 LNK2005 错误主要有以下几种情况: 1重复定义全局变量。可能存在两种情况: A、对于一些初学编程的程序员,有时候会以为需要使用全局变量的地方就可以使用定义申明一下。其实这是错误的,全局变量是针对整个工程的。正确的应该是在一个 CPP 文件中定义如下:int g_Test;那么在使用的 CPP 文件中就应该使用:extern int g_Test 即可,如果还是使用 int g_Test,那么就会产生LNK2005 错误,一般错误错误信息类似:AAA.obj error LNK2005 int book c?book3HA already defined in BBB.obj。切记的

2、就是不能给变量赋值否则还是会有 LNK2005 错误。 这里需要的是“声明”,不是“定义”!根据 C+标准的规定,一个变量是声明,必须同时满足两个条件,否则就是定义: (1)声明必须使用 extern 关键字;(2)不能给变量赋初值 所以,下面的是声明: extern int a; 下面的是定义 int a; int a = 0; extern int a =0; B、对于那么编程不是那么严谨的程序员,总是在需要使用变量的文件中随意定义一个全局变量,并且对于变量名也不予考虑,这也往往容易造成变量名重复,而造成 LNK2005 错误。 2头文件的包含重复。往往需要包含的头文件中含有变量、函数、类

3、的定义,在其它使用的地方又不得不多次包含之,如果头文件中没有相关的宏等防止重复链接的措施,那么就会产生 LNK2005 错误。解决办法是在需要包含的头文件中做类似的处理:#ifndef MY_H_FILE /如果没有定义这个宏 #define MY_H_FILE /定义这个宏 . /头文件主体内容 . #endif 上面是使用宏来做的,也可以使用预编译来做,在头文件中加入: #pragma once /头文件主体 3使用第三方的库造成的。这种情况主要是 C 运行期函数库和 MFC 的库冲突造成的。具体的办法就是将那个提示出错的库放到另外一个库的前面。另外选择不同的 C 函数库,可能会引起这个错

4、误。微软和 C 有两种 C 运行期函数库,一种是普通的函数库:LIBC.LIB,不支持多线程。另外一种是支持多线程的:msvcrt.lib。如果一个工程里,这两种函数库混合使用,可能会引起这个错误,一般情况下它需要 MFC 的库先于 C 运行期函数库被链接,因此建议使用支持多线程的 msvcrt.lib。所以在使用第三方的库之前首先要知道它链接的是什么库,否则就可能造成 LNK2005 错误。如果不得不使用第三方的库,可以尝试按下面所说的方法修改,但不能保证一定能解决问题,前两种方法是微软提供的: A、选择 VC 菜单 Project-Settings-Link-Catagory 选择 Inp

5、ut,再在Ignore libraries 的 Edit 栏中填入你需要忽略的库,如:Nafxcwd.lib;Libcmtd.lib。然后在 Object/library Modules 的 Edit 栏中填入正确的库的顺序,这里需要你能确定什么是正确的顺序,呵呵,God bless you! B、选择 VC 菜单 Project-Settings-Link 页,然后在 Project Options 的Edit 栏中输入/verbose:lib,这样就可以在编译链接程序过程中在输出窗口看到链接的顺序了。 C、选择 VC 菜单 Project-Settings-C/C+页,Catagory 选

6、择 Code Generation 后再在 User Runtime libraray 中选择 MultiThread DLL 等其他库,逐一尝试。 关于编译器的相关处理过程,参考: http:/ 这就是我所遇到过的 LNK2005 错误的几种情况,肯定还有其他的情况也可能造成这种错误,所以我不希望你在看完这篇文章以后,再遇到 LNK2005 错误时候,不动脑筋的想对号入座的排除错误。编程的过程就是一个思考的过程,所以还是多多开动你的头脑,那样收获会更多! 附录:编译器处理相关 一.预处理器-编译器-汇编器-链接器预处理器会处理相关的预处理指令,一般是以“#“开头的指令。如:#include

7、“xx.h“ #define 等。编译器把对应的*.cpp 翻译成*.s 文件(汇编语言)。汇编器则处理*.s 生成对应的*.o 文件(obj 目标文件)最后链接器把所有的*.o 文件链接成一个可执行文件(?.exe)1.部件:首先要知道部件(可以暂且狭义地理解为一个类)一般分为头文件(我喜欢称为接口,如:*.h)及实现文件(如:*.cpp)。一般头文件会是放一些用来作声明的东东作为接口而存在的。而实现文件主要是实现的具体代码。2.编译单个文件:记住 IDE 在 bulid 文件时只编译实现文件(如*.cpp)来产生 obj,在 vc 下你可以对某个?.cpp 按下 ctrl+f7 单独编译它

8、生成对应一个?.obj 文件。在编译?.cpp 时 IDE 会在?.cpp 中按顺序处理用#include 包括进来的头文件(如果该头文件中又#include 有文件,同样会按顺序跟进处理各个头文件,如此递归。)3.内部链接与外部链接:内、外链接是比较基础的东东,但是也是新手最容易错的地方,所以这里有必要祥细讨论一下。内部链接产生的符号只在本地?.obj 中可见,而外部链接的符号是所有*.obj 之间可见的。如:用 inline 的是内部链接,在文件头中直接声明的变量、不带 inline 的全局函数都是外部链接。在文件头中类的内部声明的函数(不带函数体)是外部链接,而带函数体一般会是内部链接(

9、因为 IDE 会尽量把它作为内联函数)认识内部链接与外部链接有什么作用呢?下面用 vc6 举个例子:/ 文件 main.cpp 内容:void main()/ 文件 t1.cpp 内容:#include “a.h“void Test1() Foo(); / 文件 t2.cpp 内容:#include “a.h“void Test2() Foo(); / 文件 a.h 内容:void Foo( ) 好,用 vc 生成一个空的 console 程序(File - new - projects - win32 console application),并关掉预编译选项开关(project - set

10、ting - Cagegoryrecompiled Headers - Not using precompiled headers)现在你打开 t1.cpp 按 ctrl+f7 编译生成 t1.obj 通过打开 t2.cpp 按 ctrl+f7 编译生成 t2.obj 通过而当你链接时会发现:Linking.t2.obj : error LNK2005: “void _cdecl Foo(void)“ (?FooYAXXZ) already defined in t1.obj这是因为:1. 编译 t1.cpp 在处理到#include “a.h“中的 Foo 时看到的 Foo 函数原型定义是外

11、部链接的,所以在 t1.obj 中记录 Foo 符号是外部的。2. 编译 t2.cpp 在处理到#include “a.h“中的 Foo 时看到的 Foo 函数原型定义是外部链接的,所以在 t2.obj 中记录 Foo 符号是外部的。3. 最后在链接 t1.obj 及 t2.obj 时, vc 发现有两处地方(t1.obj 和 t2.obj中)定义了相同的外部符号(注意:是定义,外部符号可以多处声明但不可多处定义,因为外部符号是全局可见的,假设这时有 t3.cpp 声明用到了这个符号就不知道应该调用 t1.obj中的还是 t2.obj 中的了),所以会报错。解决的办法有几种: a.将 a.h

12、中的定义改写为声明,而用另一个文件 a.cpp 来存放函数体。(提示:把上述程序改来试试)(函数体放在其它任何一个 cpp 中如 t1.cpp 也可以,不过良好的习惯是用对应cpp 文件来存放)。这时包括 a.h 的文件除了 a.obj 中有函数体代码外,其它包括 a.h 的 cpp 生成的 obj 文件都只有对应的符号而没有函数体,如t1.obj、t2.obj 就只有符号,当最后链接时 IDE 会把a.obj 的 Foo()函数体链接进 exe 文件中,并把 t1.obj、t2.obj 中的 Foo 符号转换成对应在函数体 exe 文件中的地址。另外:当变量放在 a.h 中会变成全局变量的定

13、义,如何让它变为声明呢?例如: 我们在 a.h 中加入:class CFoo;CFoo* obj;这时按 f7 进行 build 时出现:Linking.t2.obj : error LNK2005: “class CFoo * obj“ (?obj3PAVCFooA) already defined in t1.obj一个好办法就是在 a.cpp 中定义此变量( CFoo* obj,然后拷贝此定义到 a.h 文件中并在前面加上 extern(extern CFoo* obj如此就可通过了。当然 extern 也可以在任何调用此变量的位置之前声明,不过强烈建议不要这么作,因为到处作用 exte

14、rn,会导致接口不统一。良好的习惯是接口一般就放到对应的头文件。b. 将 a.h 中的定义修改成内部链接,即加上 inline 关键字,这时每个 t1.obj和 t2.obj 都存放有一份 Foo 函数体,但它们不是外部符号,所以不会被别的 obj 文件引用到,故不存在冲突。(提示:把上述程序改来试试)另外我作了个实验来验证”vc 是把是否是外部符号的标志记录在 obj 文件中的“(有点绕口)。可以看看,如下:(1)文件内容:/ 文件 main.cpp 内容:void main()/ 文件 t1.cpp 内容:#include “a.h“void Test1() Foo(); / 文件 t2.

15、cpp 内容:#include “a.h“void Test2() Foo(); / 文件 a.h 内容:inline void Foo( ) (2) 选 t1.cpp 按 ctrl+f7 单独编译,并把编译后的 t1.obj 修改成t1.obj_inline(3) 选 t2.cpp 按 ctrl+f7 单独编译,并把编译后的 t2.obj 修改成t2.obj_inline(4) 把除了 t1.obj_inline 及 t2.obj_inline 外的其它编译生成的文件删除。(5) 修改 a.h 内容为:void Foo( ) ,使之变为非内联函数作测试(6) rebuild all 所有文件

16、。这时提示:Linking.t2.obj : error LNK2005: “void _cdecl Foo(void)“ (?FooYAXXZ) already defined in t1.objDebug/cle.exe : fatal error LNK1169: one or more multiply defined symbols found(7) 好,看看工程目录下的 debug 目录中会看到新生成的 obj 文件。下面我们来手工链接看看,打开菜单中的 project - setting - Link,拷贝 Project options 下的所有内容,如下:kernel32.l

17、ib 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.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /

18、incremental:yes /pdb:“Debug/cle.pdb“ /debug /machine:I386 /out:“Debug/cle.exe“ /pdbtype:sept 把它修改成:Link.exe 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.lib gdi32.lib winspool.lib comd

19、lg32.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 Debug/t1.obj Debug/t2.obj Debug/main.objpause注意前面多了 Link.exe,后面多了 Debug/t1.obj Debug/t2.o

20、bj Debug/main.obj 以及最后一个 pause 批处理命令,然后把它另存到工程目录(此目录下会看到 debug目录)下起名为 link.bat运行它,就会看到:t2.obj : error LNK2005: “void _cdecl Foo(void)“ (?FooYAXXZ) already defined in t1.objDebug/cle.exe : fatal error LNK1169: one or more multiply defined symbols found很好,我们链接原来的 obj 文件得到的效果跟在 vc 中用 rebuild all 出来的效果一

21、样。那么现在如果我们把备份出来的 t1.obj_inline 覆盖 t1.obj 而 t2.obj_inline 覆盖 t2.obj再手动链接应该会是不会出错的,因为原 t1.obj_inline 及 t2.obj_inline 中存放的是内部链接符号。好运行 Link.bat,果然不出所料,链接成功了,看看 debug 目录下多出了一个 exe 文件。这就说明了内或外符号在 obj 有标志标识!(提示:上述为什么不用 vc 的 f7build 链接呢,因为文件时间改变了,build 会重新生成新的 obj,所以我们用手动链接保证 obj 不变)注 bj 信息可用 dumpbin.exe 查看

22、4.#include 规则:有很多人不知道#include 文件该放在何处?1). 增强部件自身的完整性:为了保证部件完整,部件的 cpp 实现文件(如 test.cpp)中第一个#include 的应当是它自身对应的头文件(如 test.h)。(除非你用预编译头文件, 预编译头必须放在第一个)。这样就保证了该部件头文件(test.h)所必须依赖的其它接口(如 a.h 等)要放到它对应的文件头中(test.h),而不是在 cpp 中(test.cpp)把所依赖的其它头文件(a.h 等)移到其自身对应的头文件(test.h 等)之前(因为这样强迫其它包括此部件的头文件(test.h)的文件(b.

23、cpp)也必须再写一遍 include(即 b.cpp 若要#include “test.h“也必须#include “a.h“)”。另外我们一般会尽量减少文件头之间的依赖关系,看下面:2). 减少部件之间的依赖性:在 1 的基础上尽量把#include 到的文件放在 cpp 中包括。这就要求我们一般不要在头文件中直接引用其它变量的实现,而是把此引用搬到实现文件中。例如: / 文件 foo.h:class CFoovoid Foo();/ 文件 test.h:#include “foo.h“class CTestCFoo* m_pFoo;public:CTest() : m_pFoo(NULL

24、)void Test() if(m_pFoo) m_pFoo-Foo();.;/ 文件 test.cpp:#include “test.h“.如上文件 test.h 中我们其实可以#include “foo.h“移到 test.cpp 文件中。因为 CFoo* m_pFoo 我们只想在部件 CTest 中用到,而将来想用到 CTest 部件而包括 test.h 的其它部件没有必要见到 foo.h 接口,所以我们用前向声明修改原文件如下:/ 文件 foo.h:class CFoopublic:void Foo();/ 文件 test.h:class CFoo;class CTestCFoo* m

25、_pFoo;public:CTest();void Test();/;/ 文件 test.cpp:#include “test.h“ / 这里第一个放该部件自身对应的接口头文件#include “foo.h“ / 该部件用到了 foo.hCTest:CTest() : m_pFoo(0) m_pFoo = new CFoo; void CTest:Test() if(m_pFoo) m_pFoo-Foo();/./ 再加上 main.cpp 来测试:#include “test.h“ / 这里我们就不用见到#include “foo.h“了CTest test;void main()test.Test();3). 双重包含卫哨:在文件头中包括其它头文件时(如:#include “xx.h“)建议也加上包含卫哨:/ test.h 文件内容:#ifndef _XX1_H_#include “xx1.h“#endif#ifndef _XX2_H_#include “xx2.h“#endif虽然我们已经在 xx.h 文件中开头已经加过,但是因为编译器在打开#include文件也是需要时间的,如果在外部加上包含卫哨,对于很大的工程可以节省更多的编译时间。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报