一、程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境。
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。

什么是翻译环境

将test.c源文件 -> test.exe 的过程所依赖的环境就是翻译环境,这个test.exe是二进制的文件,计算机可以直接运行的文件。一般来说翻译环境就是(编译器:cl.exe)
我们平时用的编译器列如vs2019等,是高度集成了的开发环境-IDE

什么是执行环境

执行test.exe文件所依赖的环境,一般来说执行环境就是(操作系统)

二、翻译环境编译+链接详解

在这里插入图片描述

1.每一个源文件都会通过编译过程,分别转化为目标文件(.obj)
2.这些目标为文件再由链接器捆绑在一起,形成一个单一完整的整体
3.链接器同时也会引入标准C函数库中任何被该程序所用到的函数(所以有时不引用头文件程序仍然可以正常运行),而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

链接库就是库函数依赖的库文件,或者说第三方的库

(1).编译

编译又可细分为几个部分
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/332d8643432b48aab3a63b2f917a767d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57uF5aOrwrfmsLg=,size_20,color_FFFFFF,t_70,g_se,x_16

1.预编译

预编译过程是处理的文本内容的替换,列如#define定义的符号和宏的替换,注释的删除,生成test.i文件
1.头文件的包含
2.#define定义的符号和宏的替换
3.注释的删除

原代码:
请添加图片描述

因为vs2019是集成开发环境,不宜展示编译链接的详细过程,这里采用Linux环境下gcc来展示
通过预编译指令:gcc test.c -E -o test.i进行预编译得到test.i文件,将test.i文件打开
在这里插入图片描述

可以看到这样一长串的的代码,可以发现这里进行了#define定义的符号替换,同时我们打开 stdio.h 这个文件
在这里插入图片描述

2.编译

编译过程是将编写的.c代码,转化为汇编语言,生成test.s文件
还会进行:
1.语法分析
2.词法分析
3.语义分析
4.符号汇总(只汇总全局符号)
即进行语法准确性的检测

用gcc 来展示:Linux环境下对应的文件编译指令 gcc test.i -S
请添加图片描述

可以看到生成了一个汇编文件,将源代码转化成了汇编代码

3.汇编

汇编过程是将汇编代码转化为二进制/机器指令/二进制指令,生成符号表,生成目标文件(.obj)-二进制文件

用gcc 来展示:Linux环境下对应的文件编译指令 gcc test.i -c -o test.o
请添加图片描述

可以看到生成的文件是二进制文件,我们是看不明白的。
汇编过程还会生成一个符号表,这个二进制文件是elf格式的,所以我们可以通过Linux的readelf工具来阅读二进制文件,我们选择打印符号表
请添加图片描述
通过解析后的符号表打印件我们可以看到,一个类似表格的东西,里面有main,Add等全局符号,这个就是生成的符号表

(2).链接

vs2019的链接器(link.exe)
1.合并段表
2.符号表的合并和重定位
在这里插入图片描述
段表的合并:目标文件是elf格式的,这种格式的文件会将自己分为一段一段的,段表的合并就是将其相似的部分合并在一起
符号表的合并和重定位:在汇编过程会生成符号表,每一个源文件都会生成一个符号表,这些符号表汇总了全局的的符号供我们使用,在合并的过程中,将一个符号的有效地址合并起来(就是重定位,将其无效的地址换为有效地址,用于正确的调用)。
这里就解释的为什么不包含头文件,仍然可以正常运行的问题,函数等全局符号的调用是在链接过程从生成的符号表中去找的,这时的函数名,地址信息都在一张符号表上,所以可以正常调用。

三、运行环境

程序执行的过程:

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序
    的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用main函数。
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回
    地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程
    一直保留他们的值。
  4. 终止程序。正常终止main函数;也有可能是意外终止。
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐