什么是程序?我们说的程序一般是指高级语言(C/C++/Java等),这些程序是人设计的并且人能看懂的。而计算机能看懂的只有二进制可执行文件。因此我们人写的程序,一般要通过一个编译器把高级语言翻译成一个计算机能看懂的文件,这其中涉及到了多个软件层。
计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。
以计算机为例,我们想要计算机服从指挥,就必须用计算机语言。就像我们说一句话一样,是由一个个汉字组成。那么汉字就是中文的基本单词。计算机语言也有基本单词,我们把这个单词叫做指令。汉字是由先人创造出来的,指令同样也是由人创建出来的。并且,我们把一台计算机的全部指令称为该计算机的指令集。就像中文包括了所有汉字一样。计算机指令能控制计算机,因为指令其本质是能被计算机识别并执行的二进制位串(数字)。比如1000110010100000,告诉计算机将2个数加起来。但是用这些由二进制组成的指令不仅难记而且与计算机通信也太过乏味。因此设计人员开发了助记符。(比如我们小学记英文发音用汉字标识在下面助自己记忆)有助记符,这样指令就容易记了,但是助记符还是要手工翻译成二进制指令,麻烦。随后,设计人员开发了一种称为汇编程序的软件。因此程序人员写下add A,B汇编程序会将该符号翻译成一条指令1000 1100 1010 0000该指令告诉计算机将A和B两个数相加,这种符号语言B,比如,(add A,B),就是今天的汇编语言。不知道你发现没有,这种汇编语言基本是每一句对应一条计算机可执行的指令。因此,汇编语言其实时性强、执行速度快、代码效率高。但也有缺点,汇编语言写在汇编程序这个软件上的的顺序不符合我们人的思维逻辑。这就要求程序员像计算机一样思考,写出汇编语言。麻烦,因此,又有了,C语言等多种高级语言。C语言程序等通过编译形成汇编语言,汇编语言再通过汇编形成计算机可执行指令。
1.生成一个可执行程序要经过以下几步。以Devc++,C语言,Windows32系统为例。我们首先需要新建一个.c源文件,第一步就是编辑代码,当编好代码后;第二步就是编译代码,通过编译就把人能看懂的代码翻译成计算机能看懂的目标代码也就是一个可执行程序(.exe文件)或者目标程序。
2.指令是能被计算机识别并执行的位串,就是一串二进制数字,因为计算机只能识别0/1二进制数字组成的指令,一台计算机能识别的全部指令就是指令集,指令集是由其设计厂家规定设计的比如MIPS,ARMv7。
3.目标程序本质是一个二进制文件里面包含需要计算机执行这个程序所需的全部指令。
这其中第二步编译又有四个步骤:预处理/编译/汇编/链接
gcc编译main.c为例:
预处理就是对源程序中的伪指令(以#开头的指令)和特殊符号进行处理的过程。
gcc -E main.c > main.i
《程序员的自我修养-链接、装载与库》 中写道:预编译(处理)过程主要处理那些源代码文件中的以"#"开始的预编译指令。比如 “#include”、“#define”等,主要处理规则如下:
- 将所有的“#define”删除,并且展开所有的宏定义。
- 处理所有条件预编译指令,比如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”。
- 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
- 删除所有的注释”//”和“/**/”。
- 添加行号和文件名标识,比如#2“hello.c’2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
- 保留所有的#pragma编译器指令,因为编译器须要使用它们。
编译就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码。
gcc -S main.c > main.s
汇编就是将汇编代码转变为机器可以执行的二进制代码,每一个汇编语句几乎都对应一条机器指令。
gcc -c main.c > main.o
链接在成功汇编之后,就进入链接阶段。(比如新建一个工程,其中多个.c文件一起编译,这其中只有一个.c文件有main主函数,成功汇编后就要相互链接起来)链接主要是为了解决多个文件之间符号引用的问题。编译时编译器只对单个文件进行处理,如果该文件里面需要引用到其他文件中的符号,那么这时在这个文件中该符号的地址是没法确定的,只能等链接器把所有的目标文件链接到一起,才能确定最终的地址,最终生成可执行文件。