C语言源代码转变为可执行程序的过程

Hello.c 

#include

int main()
{
  printf("Hello World\0");
  return 0;
}

 

我们在VS下只需要Ctrl+F5便能打印出Hello World,

在Linux下也只需要两行命令

  1. gcc Hello.c     

  2.    ./a.out

但程序为什么要被编译器编译之后才能运行?

因为计算机能够识别的只有机器语言,机器语言就是由二进制0和1构成。所以为了让计算机执行我们写的程序,必须翻译成计算机能够识别的机器语言程序(目标程序)。

编译器把C语言程序转换成可以执行的机器码的过程做了什么?怎么做的?

1.预处理:展开头文件/宏替换/去掉注释/条件编译 

2.编译:检查语法,生成汇编代码

3.汇编 :把汇编代码转化成二进制的机器码 

4.链接 合成可执行的程序,并对声明 在其他目标文件找到对应的定义

Linux环境下有sum.c和text.c两个源文件生成可执行文件。过程图解 

C语言源代码转变为可执行程序的过程_第1张图片

 

过程详解:

预处理过程主要处理那些源代码文件中的以“#”开始的预编译指令

  • 将所有的“#define”删除,并且展开所有的宏定义。

  • 处理所有条件预编译指令

  • 处理#include预编译指令,将包含的文件插入到该预编译指令的位置。(这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件)

  • 删除所有的注释

  • 添加行号和文件名标识,以便于编译时编译器产生的调式用的行号信息及用于编译时产生编译错误或警告时能够显示行号。

  • 保留所有的#pragma编译器指令,因为编译器须要使用它们。

编译:

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件。

编译器就是将高级语言翻译成机器语言的一个工具

编译过程一般可以分成6步:扫描、语法分析(语法树)、语义分析、源代码优化、代码生成和目标代码优化

编译器所能分析的语义是静态语义(即在编译期可以确定的语义){动态语义:只有在运行期才能确定的语义。},包括:声明和类型的匹配,类型的转换。

汇编:

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎对应一条机器指令。

链接:

把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确的衔接。

链接过程主要包括地址和空间分配、符号决议和重定位等这些步骤。

重定位所做的就是给程序中每个这样的绝对地址引用的位置“打补丁”,使它们指向正确的地址。

 

链接的接口--------符号

链接过程的本质就是要把多个不同的目标文件之间相互粘到一起。

在链接中,目标文件之间相互拼合实际上是目标文件之间对地址的引用,即对函数和变量的地址的引用

在链接中,我们将函数和变量统称为符号,函数名和变量名就是符号名

每一个目标文件都会有一个相应的符号表,这个表里面记录了目标文件中所用到的所有符号,每个定义的符号有一个对应的值,叫做符号值,对于变量和函数来说,符号值就是它们的地址、


 

 

你可能感兴趣的:(程序员的自我修养,C/C++)