本章的内容同第一章一样较为简短。具体可见下方的思维导图。
2.1 环境
环境的分类
- 翻译环境:源代码被转换为可执行的机器指令(源代码->机器指令)。
- 执行环境:实际执行代码。
- 交叉编译器:一台机器上运行,产生的代码可运行于不同类型的机器上(一对多)。
- 独立环境:不存在操作系统的环境,典型的就是嵌入式系统。
2.1.1 翻译
此过程在《操作系统》中有详细的描述,所以在此作为重点一并学习。这个过程通俗地讲,就是我们的自己编写的代码如何一步步地进入到电脑的CPU中进行处理的。如下图所示(参考资料:《深入理解计算机系统》)。
可以看出,程序的“翻译”,大概经过了预处理、编译、汇编和链接四个过程。
- 预处理阶段,读取了头文件中的内容,也就是我们平时编写C语言时候的.h文件。
- 编译阶段,对我们编写的代码进行逐条分析,检查是否有词法或者语法错误,如果有,则会提醒用户,还会对我们的代码进行优化,优化指的是会将代码进行再处理,以便CPU可以更好地执行。然后生成XXX.s文件。
- 汇编阶段,将中间生成的汇编程序翻译成机器指令,并按照既定的规则进行打包。虽然机器是CPU可直接执行的指令,但是这时候还需要最后一步——链接。
- 在我们的程序中,有时候会有各种各样的链接库文件(比如上图中的YYY.o),比方说静态链接库和动态链接库文件,而这样的链接库文件本身就是编译好的,所以此时可直接与当前工程中的代码进行合并。最终生成可执行文件。
经过以上的步骤,程序便可由外存进入内存进行执行。
2.1.2 执行
- 首先,由操作系统将我们编写的程序文件从外存载入到内存中,对没有存储在堆栈中的,尚未初始化的变量进行初始化。
- 然后,便可以开始运行程序,绝大多数时候,程序会使用一个运行时堆栈,用于存储函数的局部变量和返回地址,这样才能顺利实现函数的调用和返回。程序同时可也可以使用静态内存,该内存中的变量在程序的整个执行过程中将一直保留它们的值。
- 最后,是程序的终止,导致程序终止的原因有很多,有可能是程序正常执行完毕,有可能是抛出异常,也有可能是出现错误。
2.2 词法规则
这部分主要讲了C语言的“词法规范”,以及C语言本身如何处理语法中的一些歧义问题。比方说最常见的就是转义字符串。
2.3 程序风格
若说上一部分是C语言的“词法规范”,那这句就像是C语言的“语法规范”。类似于高中讲的作文格式。有两点比较重要。
- 一般C语言的缩进是以Tab键按下的空格数作为其大小的,当缩进过多的时候,代码月都困难,这时候就可以采用函数嵌套的方式来解决。
- 在大型的工程开发中,函数的名称非常多,这样,各个函数找起来相当麻烦,所以就可以将返回值类型与函数名放在不同的行,便于找到。例如:
#include <stdio.h> #include <stdlib.h> int add(int a, int b) { return a + b; } int main() { printf("%d",add(10, 20)); system("pause"); }
可以将其替换为:
#include <stdio.h> #include <stdlib.h> int add(int a, int b) { return a + b; } int main() { printf("%d",add(10, 20)); system("pause"); }
自己不是很常用这种方式,看着较为别扭。
---------------------------END---------------------------