首先要思考问什么要编译与链接,首先这是一个如何把源程序即写好的代码编程可执行文件的过程,简单的加工模型如下图:
这是一个简单的加工模型,比较直观,但是有一个问题,就是如果对源程序进行修改,则需要全部进行重新加工,还有就是加工耗时长, 即无法处理大型的、工业级的程序,那么如何处理呢?一个典型的方法是分块处理,方法模型图如下:
首先将源文件分块为若干个块,并把每个块编译为目若干个目标文件,最后链接为可执行程序。这样的好处编译耗资源但是一次处理的输入较少,然后链接输入较多但是处理速度较快,并且比较方便程序的修改。
上面是设计编译和链接想要解决什么样的问题,因为这样的设计所以会产生许多的所谓的规则定义。
1、定义和声明,包含函数、变量的定义和声明,比如我在源文件1中定义的一个变量a,但我在源文件2中也会用到,这个时候就需要在源文件2中进行声明,这样做的目的是为了让编译器在目标文件链接的时候能将其关联起来,知道源文件2声明的变量a是在源文件1中定义的,变量和函数都如此。
2、头文件和源文件,这个概念是为了解决什么问题呢?比如我在源文件1中定义了100个变量,我其他源文件2、3、……、N都可以用得到,那么按照之前定义和生命的概念需要在每个源文件中进行声明,是不是太麻烦了?所以有了头文件的概念,把声明放在单独的头文件中,然后源文件直接引用该头文件,编译器在编译的时候会帮你自动展开,省去自己的重复声明。当然头文件中可以进行声明,也可以进行定义,源文件则是对头文件的引用,涉及具体的实现。
3、翻译单元:翻译单元是什么?我的理解比如temp.h和temp.cpp,其中temp.h里面所有包含其他头文件进行展开,然后忽略掉预处理语句,这样加在一起就是一个翻译单元。
在实际的程序中,整个流程如下:
1、预处理:把源文件变成翻译单元,即进行头文件展开和去掉预处理语句。注意的是,需要防止头文件被渲染展开,有两种方法一种#ifdef,一种#pragma once。翻译单元后缀 i 。
2、编译:把预处理出来的文件编译生成汇编代码,产出文件后缀.s。
3、汇编:把汇编代码翻译成目标文件,即机器码,产出文件后缀.o。
4、链接:把目标文件放到一起进行链接。