为何未显式包含源文件,Visual Studio仍报重复定义错误?
咱们先把你的场景理清楚:你用VS2019建了C控制台项目,Main.cpp里定义了全局变量int i = 10;,之后在源文件文件夹加了个File2.cpp,里面只有int i = 2;,你明明没在Main.cpp里#include "File2.cpp",编译却报了“one or more multiply defined symbols found”的错;但把File2.cpp换成头文件文件夹里的File2.h(内容同样是int i = 2;),编译就正常了。这背后是C编译链接的核心规则在起作用。
第一个问题:为什么没#include也会报错?
Visual Studio的C++项目默认会自动把所有添加到项目中的源文件(.cpp、.c这类后缀)都纳入编译流程,不管你有没有用#include去引用它们。也就是说:
Main.cpp会被单独编译成Main.obj,里面包含了全局变量i的定义(int i=10)File2.cpp也会被单独编译成File2.obj,里面也有一个全局变量i的定义(int i=2)
当链接器把这两个目标文件合并成最终的可执行文件时,它发现两个完全相同的全局符号i(全局变量的名字就是它的符号名),根据C++的规则,全局变量只能有一个定义,所以链接器就抛出了多重定义的错误。
第二个问题:为什么换成头文件就正常了?
你把int i=2放到File2.h里,而且没有在任何源文件里#include "File2.h",那这个头文件根本就没被引入到编译过程中。整个项目里只有Main.cpp被编译,里面只有一个i的定义,链接器自然找不到冲突,编译就通过了。
不过这里要提个醒:这种头文件里直接定义全局变量的写法是非常危险的!如果之后你在某个源文件里#include "File2.h",那么这个头文件的内容会被完整复制到那个源文件里,编译后对应的目标文件就会多出一个i的定义,链接时又会触发多重定义错误。正确的做法是:
- 在头文件里用
extern int i;做声明(告诉编译器“这个变量在别的地方定义了”) - 在某一个源文件里(比如
File2.cpp)写int i=2;做定义
这样不管多少个源文件包含这个头文件,都只会有一个i的定义,就不会有冲突了。
内容的提问来源于stack exchange,提问作者MrSnrub

