“error LNK2005: 已经在*.obj中定义”
这是一个重复定义错误 ,造成LNK2005主要有以下几种情况:
1.全局变量的重复定义。
可能存在两种情况:
情况A:全局变量在.cpp文件中的多次声明
我们首先在一个cpp用到了一个全局变量a(10),会定义如下:
int a=10;
在其他的cpp文件中继续使用该变量只需要声明:
extern int a;
如果还是使用int a
,那么就会产生LNK2005错误。
此外,声明的的时候不要给变量赋值(赋值就成了定义),否则还是会有LNK2005错误:
extern int a=10;
根据C++标准,一个变量是声明,必须同时满足两个条件,否则就是定义:
- (1)声明必须使用extern关键字
- (2)不能给变量赋初值
所以,下面的是声明:
extern int a;
下面的是定义
int a;
int a = 0;
extern int a =0;
情况B:
对于那些粗心随意的程序员,总是在需要使用变量的cpp文件中随意定义一个全局变量 int a = 0;
,在下一个文件中又无意用到了一个“新的a” int a = 0;
,这造成了变量名重复LNK2005错误。
2.头文件的包含重复。
一般,头文件中含有变量、函数、类的定义
- 重复引用头文件,那么就会产生LNK2005错误。
解决方案:
在需要包含的头文件中做类似的处理:
#ifndef MY_H_FILE //如果没有定义这个宏
#define MY_H_FILE //定义这个宏
……. //头文件主体内容
…….
#endif
上面是使用宏来做的,也可以使用预编译来做,在头文件中加入:
#pragma once
//头文件主体
3.头文件中的重定义
新手经常忽略的一个细节。举例说明:
在头文件中声明了一个简单的Cube类(注意里面的int getV();
):
class Cube
{
public:
Cube();
~Cube();
void setA(int a)
{
m_a = a;
};
void setB(int b)
{
m_a = b;
};
void setC(int c)
{
m_a = c;
};
int getV();//声明了getV().想要在外部单独定义
private:
int m_a;
int m_b;
int m_c;
int m_v;
};
紧接着,在类这个结构体下面定义int getV():
int Cube::getV()
{
m_v = m_a * m_b * m_c;
return m_v;
};
一运行:
为什么呢?
- 因为Cube::的缘故,应该是编译器又内联了一次Cube类,造成了重定义。
解决方案:
- 1.像
void setC ()
一样,在类结构体的内部一起定义(适用于简单的小代码)。 - 2.在实际的项目开发中,通常将声明和定义分开。将定义写到头文件对应`的.cpp中。
注意:
《C++Primer》第四版 2.3.5节中这么说到:
①变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。
②变量声明:用于向程序表明变量的类型和名字。
③定义也是声明:当定义变量时我们声明了它的类型和名字。
④extern关键字:通过使用extern关键字声明变量名而不定义它。
程序设计风格:
不要把变量定义放入.h文件,这样容易导致重复定义错误。 尽量使用static关键字把变量定义限制于该源文件作用域,除非变量被设计成全局的。 可以在头文件中声明一个变量,在用的时候包含这个头文件就声明了这个变量。
总结:
变量在使用前就要被定义或者声明。 在一个程序中,变量只能定义一次,却可以声明多次。 定义分配存储空间,而声明不会。
4.使用三方库的问题。
这种情况主要是C运行期函数库和MFC的库冲突造成的。
- 微软和C有两种C运行期函数库,一种是普通的函数库:LIBC.LIB,不支持多线程。另外一种是支持多线程的:msvcrt.lib。如果一个工程里,这两种函数库混合使用,可能会引起这个错误,一般情况下它需要MFC的库先于C运行期函数库被链接,因此建议使用支持多线程的msvcrt.lib。
所以在使用第三方的库之前首先要知道它链接的是什么库,否则就可能造成LNK2005错误。
- 可以选择VC菜单Project->Settings->Link页,然后在Project Options的Edit栏中输入/verbose:lib,这样就可以在编译链接程序过程中在输出窗口看到链接的顺序了。
解决方案:
- 已知正确顺序,忽略错误库:
选择VC菜单Project->Settings->Link->Catagory选择Input,再在Ignore libraries 的Edit栏中填入你需要忽略的库,如:Nafxcwd.lib;Libcmtd.lib。然后在Object/library Modules的Edit栏中填入正确的库的顺序,这里需要你能确定什么是正确的顺序
- 不求甚解,疯狂尝试,只为成功:
选择VC菜单Project->Settings->C/C++页,Catagory选择Code Generation后再在User Runtime libraray中选择MultiThread DLL等其他库,逐一尝试。
- 不求代价,只为成功编译运行:
使用代码执行命令强制执行/force:multiple
参考文献:
https://blog.youkuaiyun.com/ivyivyjackjack/article/details/5331532
https://www.cnblogs.com/MuyouSome/p/3332699.html