error:LNK2005 已经在*.obj中定义 的原因分析及对策

本文详细阐述了LNK2005错误在C++编程中的常见原因,包括全局变量的重复声明、头文件包含重复以及使用三方库时可能出现的问题。提供了解决方案,如#ifndef/pragmaonce预编译、正确声明与定义分离以及链接库顺序管理。
摘要由CSDN通过智能技术生成

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类,造成了重定义。

解决方案

  1. 像void setC()一样,在类结构体的内联一起定义。
  2. 在实际的项目开发中,通常将声明和定义分开。将定义写到头文件对应的.cpp中。

注意:

《C++Primer》第四版中变量&声明

《C++Primer》第四版中是这么说的:

  • 变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。
  • 变量声明:用于像程序表明变量的类型和名字。
  • 定义也是声明:当定义变量时,我们声明了它的类型和名字。
  • extern关键字:通过使用extern关键字声明变量名而不定义它。

程序设计风格

  • 不要把变量定义放在.h文件,这样容易导致重复定义错误。
  • 尽量使用static关键字把变量定义限制于该源文件的作用域,除非变量被设计成全局的。
  • 可以在头文件中声明一个变量,在用的时候包含这个头文件就声明了这个变量。

总结

  1. 变量在使用前就要被定义或声明;
  2. 一个程序中,变量只能定义一次,却可以声明很多次。
  3. 定义分配存储空间,而声明不会。

使用三方库的问题

这种情况主要是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

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安心学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值