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

本文深入解析LNK2005错误的原因,包括全局变量重复定义、头文件包含重复、头文件中重定义及三方库冲突等问题,并提供详细的解决方案,帮助开发者有效避免和解决这一常见编译错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

“error LNK2005: 已经在*.obj中定义”

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

### 解决 Visual Studio 错误 LNK2005 错误 `LNK2005` 表明链接器检测到多个相同符号的定义。具体来说,在 `.obj` 文件中发现了重复的 `_main` 函数定义[^1]。 当遇到此类问题时,通常是因为存在两个或更多源文件都包含了相同的全局函数或变量声明。这可能是由于头文件管理不当或者库文件被多次引入造成的。对于当前情况中的反序函数(假设为 `reverse`),如果该函数在不同对象文件(如 OpenCVFi.obj 和 HalconFi.obj)中有实现,则会触发此错误。 为了修复这个问题: - **检查命名冲突**:确认是否有其他地方也实现了名为 `reverse` 的函数,并且这些实现在不同的编译单元里。如果有,请重命名其中一个版本以避免名称冲突。 - **静态作用域调整**:考虑将局部使用的辅助功能标记为 static 类型,这样它们就只会在单个翻译单位内部可见,从而防止外部访问引发多重定义的问题。例如: ```cpp static cv::Point_<double> reverse(const cv::Point_<double>& point); ``` - **预处理器指令控制**:利用宏来确保某些代码片段仅在一个位置生效。比如可以采用如下方式包裹可能引起冲突的部分: ```cpp #ifndef REVERSE_FUNCTION_DEFINED #define REVERSE_FUNCTION_DEFINED // Function definition here... #endif /* !REVERSE_FUNCTION_DEFINED */ ``` 另外值得注意的是,有时第三方库之间也可能发生类似的冲突。在这种情况下,应该仔细审查项目设置以及所涉及的所有库之间的关系,必要时移除不必要的依赖项[^2]。 最后,考虑到特定环境下的配置差异,建议查看项目的属性页,特别是 C/C++ -> 常规 -> 额外包含目录和链接器 -> 输入 -> 额外依赖项这两处设定,排除任何可能导致重复定义的因素[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值