作者:灵剑
链接:https://www.zhihu.com/question/280665935/answer/468734085
来源:知乎
C时代的时候编译器比较简单,是固定的编译和链接两个过程,编译一次只处理一个文件,进行预处理之后,头文件会插入到这一个文件里,不同源代码文件的处理时独立的,这样如果头文件里面定义了一个函数的实现,编译的时候所有引用这个头文件的源码文件,生成的obj里都会有这个符号。
而链接是通用的链接程序,从汇编时代就用的工具,没有什么高级功能,同一个符号链接时出现两次是会报错的。但是,我们又说了,每个文件的编译是独立的,所以如果实现不在当前源文件里面,调用的时候编译器就不知道这个函数的类型和签名,没法生成调用代码,所以必须在调用之前先声明一遍。如果不把声明写在头文件里面,就必须在每个用到这个函数的源文件里都声明一遍,很不方便,所以综合之后的解决方案就是实现写源码文件里面,声明写头文件里面。
C++只是沿用了这个设计而已,实际上现在的C++编译器有处理符号重复定义的能力了(例如inline函数可以定义在头文件里面,但不必真的inline,也不需要像static函数一样每个文件生成一个符号),但是传统也是很重要的。你的另一个问题,C调用DLL明明就是直接引用一个头文件啊……如果启用了预编译指令,一般还可以直接在头文件中指定链接一个外部库;否则需要额外链接一个obj文件,里面负责加载DLL。如果用动态的方式,则需要自己调用相应的API去加载DLL,获取导出点之类。
这个回答是从编译器的角度来说明为什么要区分头文件和源文件,而另外一个回答是从工程的角度。
一种最朴素的接口与实现分离的思想,
网友评论