LNK2005是一个重复定义错误,造成LNK2005主要有以下几种情况:
目录
全局变量的重复定义
情况A:全局变量在.cpp文件中的多次声明
情况B:变量名重复
头文件的包含重复
解决方案
#ifndef标识符宏定义
pragma once预编译
头文件中的重定义
问题出现案例
案例报错原因
解决方案
《C++Primer》第四版中变量&声明
程序设计风格
总结
使用三方库的问题
解决方案
已知正确顺序,忽略错误库
不求甚解,疯狂尝试,只为成功
不求代价,只为成功编译运行
全局变量的重复定义
全局变量可能存在两种情况:
情况A:全局变量在.cpp文件中的多次声明
我们首先在一个cpp用到了一个全局变量a(10),会定义如下:
int a = 10;
在其他的cpp文件中继续使用该变量只需要声明:
extern int a;
如果我们需要在另一个cpp文件中使用int a,那么就会产生LNK2005错误。
此时,在其他cpp文件声明的时候不要给变量赋值(赋值就成了定义),否则还是会有LNK2005的错误。
extern int a = 10;
根据C++标准,一个变量是声明,必须同时满足两个条件,否则就是定义:
- 声明必须使用extern关键字
- 不能给变量赋初值
所以,下面的是声明:
extern int a;
下面的是定义:
int a;
int a = 0;
extern int a =0;
情况B:变量名重复
对于粗心的我来说,总是在需要使用变量的cpp文件中随意定义一个全局变量 int a =0;,在下一个文件中又无意用到了一个新的a “int a = 0”,这造成了变量名重复的LNK2005错误。
头文件的包含重复
一般,头文件含有变量、函数、类的定义。
重复引用头文件,那么就会产生LNK2005错误。
解决方案
#ifndef标识符宏定义
在需要包含的头文件中做类似的处理:
#ifndef MY_H_FILE
//如果没有定义这个宏
#define MY_H_FILE
//定义这个宏
//...code...头文件主体内容
//...code...
endif
pragma once预编译
上面是使用宏来做的,也可以使用预编译来做,在头文件中加入:
#pragma once
//...code...头文件主体
头文件中的重定义
问题出现案例
我经常忽略的一个细节,举例说明:
在头文件中声明了一个简单的类(注意里面的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类,造成了重定义。
解决方案
- 像void setC()一样,在类结构体的内联一起定义。
- 在实际的项目开发中,通常将声明和定义分开。将定义写到头文件对应的.cpp中。
注意:
《C++Primer》第四版中变量&声明
《C++Primer》第四版中是这么说的:
- 变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。
- 变量声明:用于像程序表明变量的类型和名字。
- 定义也是声明:当定义变量时,我们声明了它的类型和名字。
- extern关键字:通过使用extern关键字声明变量名而不定义它。
程序设计风格
- 不要把变量定义放在.h文件,这样容易导致重复定义错误。
- 尽量使用static关键字把变量定义限制于该源文件的作用域,除非变量被设计成全局的。
- 可以在头文件中声明一个变量,在用的时候包含这个头文件就声明了这个变量。
总结
- 变量在使用前就要被定义或声明;
- 一个程序中,变量只能定义一次,却可以声明很多次。
- 定义分配存储空间,而声明不会。
使用三方库的问题
这种情况主要是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