error LNK2005

来源:互联网 发布:伟大的艺术家 知乎 编辑:程序博客网 时间:2024/04/30 11:39

为什么会出现这个错误??“error LNK2005: 已经在aaa.obj中定义”
 编程中经常能遇到LNK2005错误——重复定义错误,其实LNK2005错误并不是一个很难解决的错误。弄清楚它形成的原因,就可以轻松解决它了。   
    
  造成LNK2005错误主要有以下几种情况:   
  1.重复定义全局变量。可能存在两种情况:   
  A、对于一些初学编程的程序员,有时候会以为需要使用全局变量的地方就可以使用定义申明一下。其实这是错误的,全局变量是针对整个工程的。正确的应该是在一个CPP文件中定义如下:int   g_Test;那么在使用的CPP文件中就应该使用:extern   int   g_Test即可,如果还是使用int   g_Test,那么就会产生LNK2005错误,一般错误错误信息类似:AAA.obj   error   LNK2005   int   book   c?   already   defined   in   BBB.obj。切记的就是不能给变量赋值否则还是会有LNK2005错误。   
                这里需要的是“声明”,不是“定义”!根据C++标准的规定,一个变量是声明,必须同时满足两个条件,否则就是定义:   
  (1)声明必须使用extern关键字;(2)不能给变量赋初值   
  所以,下面的是声明:   
  extern   int   a;   
  下面的是定义   
  int   a;   int   a   =   0;   extern   int   a   =0;   
  B、对于那么编程不是那么严谨的程序员,总是在需要使用变量的文件中随意定义一个全局变量,并且对于变量名也不予考虑,这也往往容易造成变量名重复,而造成LNK2005错误。   
    
  2.头文件的包含重复。往往需要包含的头文件中含有变量、函数、类的定义,在其它使用的地方又不得不多次包含之,如果头文件中没有相关的宏等防止重复链接的措施,那么就会产生LNK2005错误。解决办法是在需要包含的头文件中做类似的处理:#ifndef   MY_H_FILE       //如果没有定义这个宏   
  #define   MY_H_FILE       //定义这个宏   
  …….       //头文件主体内容   
  …….   
  #endif   
  上面是使用宏来做的,也可以使用预编译来做,在头文件中加入:   
  #pragma   once   

  //头文件主体   

 

  3.使用第三方的库造成的。这种情况主要是C运行期函数库和MFC的库冲突造成的。具体的办法就是将那个提示出错的库放到另外一个库的前面。另外选择不同的C函数库,可能会引起这个错误。微软和C有两种C运行期函数库,一种是普通的函数库:LIBC.LIB,不支持多线程。另外一种是支持多线程的:msvcrt.lib。如果一个工程里,这两种函数库混合使用,可能会引起这个错误,一般情况下它需要MFC的库先于C运行期函数库被链接,因此建议使用支持多线程的msvcrt.lib。所以在使用第三方的库之前首先要知道它链接的是什么库,否则就可能造成LNK2005错误。如果不得不使用第三方的库,可以尝试按下面所说的方法修改,但不能保证一定能解决问题,前两种方法是微软提供的:   
  A、选择VC菜单Project->Settings->Link->Catagory选择Input,再在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选择Code   Generation后再在User   Runtime   libraray中选择MultiThread   DLL等其他库,逐一尝试。   
  关于编译器的相关处理过程,参考:   
  http://www.donews.net/xzwenlan/archive/2004/12/23/211668.aspx   
    
  这就是我所遇到过的LNK2005错误的几种情况,肯定还有其他的情况也可能造成这种错误,所以我不希望你在看完这篇文章以后,再遇到LNK2005错误时候,不动脑筋的想对号入座的排除错误。编程的过程就是一个思考的过程,所以还是多多开动你的头脑,那样收获会更多

出处http://www.cnblogs.com/lidabo/archive/2012/12/07/2807816.html


vs:有关某变量已经在???.obj中定义的错误的解决
该问题应该很多菜鸟和高手都会遇到。虽然我已精通c,但是仍时不时受制于编译器,有些错误的确是疏忽或者没休息好,太着急写代码导致的。而有些则是编译器和语法与生俱来的问题了,前2天还遇到了类模板实现和定义分离的问题折麽。语法这种东西,我认为是由于技术限制无法解决的逻辑矛盾和分析矛盾,因此我认为他们最终给都可以被智能的编译器消除,语法就是人造的,半逻辑的东西,纯粹追求语法无意义,编译器更新总是更好的,想起来最开始的编译器给的限制真是多,比如很早的时候printf不能自己处理16位32位整数,书上还给出了“正确”做法,不过现在编译器早不会有这种bug了。
回归正题,今天编程时遇到了某变量已经在???.obj中定义的错误(都可以说是bug了,好恶心),这个错误原因编译器已经说得很明确,就是重复包含变量的定义了,该变量在某头文件里声明和定义,被多个cpp包含,就会出问题,1个cpp倒是好解决的。看遍网上说法,经典的做法是不在h文件定义全局变量,或者把h文件内容移到cpp,这个有点绝,因为我的工程里的2个cpp就是需要重复使用头文件,放出来岂不是定义2次,太麻烦不喜欢用,因此我开始自己探索如果破除编译器的限制,摸索出能编译通过的方法,纠正编译器的坏毛病!(说白了还是不够智能)。这期间,我试过#pragma once #ifdef#endif 这些我都知道怎么用,不过解决不了问题,网上的回答水平还是比较初级的,自己摸索吧。网上有人说这是个初级问题,初学者才犯,不过也没提出什么高雅的解决方法,是不是高手还是要看会不会解决问题的,问题谁都会碰到,看到有很多所谓高手遇到这种问题不也是只能用下下等方法解决。最终摸索出来如下方法(过程就不说了),且摸索出原理是:编译器在头文件遇到变量定义声明时,会直接连接到obj中,此时你在同一个工程的不同cpp里多次包含同一个头文件,编译器就会说重复定义了这个变量,通俗点说法就是这些cpp共同分享了这个变量;而遇到类型定义,比如定义一个类,那么你在各个不同的cpp里都包含多次都是没什么问题的,也就是说类型定义是不在cpp之间共享的。
但是你不要断章取义,在同一个cpp里多次无意的包含了同一个h文件会提示重定义,此问题可以通过#ifdef 解决,而我说的是不同cpp文件各自包含一次h,这样是没问题的。这只是h文件仅含类型定义的时候啊,别搞错了,如果h文件仅含有变量定义声明,那么整个工程只能有一个cpp包含这个h,其他cpp若想使用则只需用extern 引入该变量即可。如果有第二个cpp包含该文件,则编译器会提示某变量已经在x.obj文件中定义了,你会发现x.cpp包含了该h。

首先,作出如下假设:你有一个1.h需要重复包含,其中有类型定义和全局变量,同时有1.cpp 2.cpp .....主函数在哪里不重要,再假设没有头文件重复包含的情况(该情况也没什么,无非在看懂本文后自己多添几行#ifdef了)。为了简单起见,假设1.h文件内容如下:
#include <windows.h>
class my
{
int i;
};
BOOL (WINAPI* closehandle)(HANDLE hObject)=CloseHandle;
int i=0;

3个cpp分别对应3种可能情况:
假设3.cpp内容如下:3.cpp只用到了变量i
void func1()
{
i=1;//这个i就是想用的头文件定义的i了
}
假设2.cpp内容如下:2.cpp用到了变量i和类类型my
void func()
{
i=1;
my me;
}
假设1.cpp内容如下:1.cpp只用到了类类型my
void main()
{
my me;
]

上面是一个类my的定义,下面是变量closehandle和i的定义了
此时我们需要把类型和变量分开,始终要记得类型可以重复包含(别断章取义),变量只能包含一次。为此设置2个预编译宏做区分,修改1.h为如下所示:
#include <windows.h>
#ifdef _DefineMyStruct//防止类型重复包含
class my
{
int i;
};
#endif

#ifdef _DefineMyVariable//防止变量定义声明重复包含
BOOL (WINAPI* closehandle)(HANDLE hObject)=CloseHandle;
int i=0;
#endif


现在来分析:由于 变量类型只能包含一次,因此只能有一处#define _DefineMyVariable,其他地方必须为#undef _DefineMyVariable
我们可以把这个机会给2.cpp(当然其他cpp也可以),2.cpp还用了类类型,同时包含了变量i的声明还不算完,需要用extern将其引入。所以代码如下:
#define _DefineMyStruct
#define _DefineMyVariable
#include "1.h"
extern int i;
extern decltype(closehandle) closehandle;
void func()
{
i=1;
my me;
}

3.cpp由于只用到了变量,且变量已经“包含”给2.cpp,因此已经通用,用extern引入即可,代码如下:
extern int i;
void func1()
{
i=1;
}

1.cpp由于只用到类类型,需要include头文件了,代码如下:
#include <windows.h>
#define _DefineMyStruct
#undef _DefineMyVariable
#include "1.h"
void main()
{
my me;
}

http://hi.baidu.com/lichao890427/item/e247a1b33c9547442bebe3e8

0 0