曾经多次在写程序时遇到这个问题,每次遇到这个问题就积累一下
首先这类问题的原因在于链接的时候出错,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文件。
注意:所以在编程时,头文件中引用头文件,定义全局变量,一定要慎重考虑,而源文件中就没有这么多顾虑了。