重定义问题的解释

曾经多次在写程序时遇到这个问题,每次遇到这个问题就积累一下

首先这类问题的原因在于链接的时候出错,VS在编译的过程中,项目中所有的cpp都会生成一个对应的obj文件,也就是一个cpp文件会生成一个.obj的可重定位目标文件,和linux中用命令g++ -c .cpp一样,得到cpp文件的单独的二进制文件,接下来就是把多个obj文件链接成一个可执行文件。不管VS还是linux的g++编译器,都是一个cpp文件生成一个obj或者o文件。

错误都是现实XXX.obj文件中已经定义,所以不是语法的问题,是多个obj文件中有相同的内容。

1.error LNK2005: "int a" (?a@@3HA) 已经在 A.obj 中定义

详细解释看链接http://www.cnblogs.com/chhlong/p/3192013.html

也就是在一个大程序中,一个头文件如果既被其他头文件或者主程序引用不止一次,那么在该头文件中不能定义全局变量和全局函数。

 

2.error LNK2005: "int __cdecl test3(void)" (?test3@@YAHXZ) 已经在 main.obj 中定义

使用的是VS2013编译器,该项目结构如下

其中main.cpp程序如下

#include <iostream>
#include "test.cpp"
using namespace std;

int main(void)
{
	
	test3();
	system("pause");
	return 0;
}

test.cpp程序如下

#include <iostream>

extern int a;
static int b = 100;

int test3()
{
	std::cout << a << std::endl;
	return a;
}

这里的错误有两点:

1.没有函数原型声明,这个声明应该加到cpp文件的函数定义前面。(但是加了以后还是不对,这是错误2造成的)

2.这个错误才是整个错误的核心,在这个函数中使用了很少见得include cpp文件,这样原理上是可以的,但是问题出在链接步骤上了。

首先要明确的前提:

VS在编译的过程中,一个cpp文件会生成一个.obj的可重定位目标文件,和linux中用命令g++ -c .cpp一样,得到cpp文件的单独的二进制文件,接下来就是把多个obj文件链接成一个可执行文件。不管VS还是linux的g++编译器,都是一个cpp文件生成一个obj或者o文件。

以上的例子中就生成了两个obj文件main.obj和test.obj文件。但是由于main.cpp文件中include了test.cpp文件,在预处理时,#include "test.cpp"就会被test.cpp文件中的具体内容给替换,所以main.obj和test.obj两个二进制文件中都有test.cpp中的内容,因此在链接时,是将这两个obj合并成一个obj,这样就会产生函数或者变量的重定义,比如这个程序中就两次定义了test3函数。

解决办法:第一种include头文件,这样在main.cpp文件预处理时,复制的内容就是头文件的内容,就不会产生变量或者函数的重定义。因为头文件是不会生成obj文件的。

第二种办法,在test3函数前加inline,变为内置函数,具体原理不明,但是尝试可以使用

第三种办法,将test.cpp从工程中去除

也就是在这里删除test.cpp,但不要删除源文件,继续include,这样只会产生一个main.obj文件。

注意:所以在编程时,头文件中引用头文件,定义全局变量,一定要慎重考虑,而源文件中就没有这么多顾虑了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值