c++编译和链接的过程,有助于理解常见的编译错误
1.预编译
这一步可以粗略的理解为只做一件事“宏展开”,#include会用源文件替换。
2.编译
编译器通过后缀名来辨识是否编译该文件,因此“.h”的头文件一概不理会,而“.cpp”的源文件一律都要被编译.
编译是一个个独立的文件作为单元的,一个文件就会编译出一个目标文件,这一点很重要,因此编译只负责本单元的事情,而对外部的事情一概不理会。在这里,我们可以调用一个函数而不必给出这个函数的定义,但是要在调用前得到这个函数的声明。其实这就是include的本质,不就是为了给你提前提供个声明而好让你使用吗?至于那个函数到底是如何实现的,需要在链接这一步里去找函数的入口地址。
因此,提供声明的方式可以是用include把放在别的文件中的声明拿过来,也可以是在调用之前自己写一句void max(int,int);)
3.链接
它会把所有编译好的单元全部链接为一个整体文件,其实这一步可以比作一个“连线”的过程,比如A文件用了B文件中的函数,那么链接的这一步会建立起这个关联。链接时最重要的我认为是检查全局空间里面是不是有重复定义或者缺失定义。这也就解释了为什么我们一般不在头文件中出现定义,因为头文件有可能被释放到多个源文件中,每个源文件都会单独编译,链接时就会发现全局空间中有多个定义了。
4.内部链接和外部连接(https://blog.csdn.net/zhanglianpin/article/details/6845818)
除此之外,还有个内部链接和外部链接。
- 内部连接 如果一个名称对于它的编译单元来说是局部的, 并且在连接的时候不可能与其它编译单元中的同样的名称相冲突,则这个名称具有内部连接.即具有内部连接的名称不会被带到目标文件中.
举个例子:
比如说定义了一个static的变量,它在连接的时候,就不会去跨object去搜索。所以也不会发生冲突
- 外部连接 在一个多文件程序中,如果一个名称在连接时可以和其他编译单元交互,那么这个名称就具有外部连接. 即具有外部连接的名称会引入到目标文件中,由连接程序进行处理.这种符号在整个程序中必须是惟一的.
- 具有内部连接的定义包括:
1.加 static 前缀的全局变量定义.如: static int x;
2.枚举类型的定义.如: enum Boolean {NO,YES };
3.类的定义. 如: class Point { int d_x; int d_y; ... };
内联函数的定义.如: inline int operator==(const Point& left,const Point&right) { ... }
union的定义.
名字空间中const常量定义