一.程序的翻译环境和执行环境
在ANSI C(标准c)的任何一种实现中,存在两个不同的环境。
计算机是能够执行二进制指令的,但是我们写出的c语言代码是文本信息,计算机不能直接理解
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。c语言的代码--》二进制指令,会放入可执行程序中(编译+链接生成.exe可执行程序)第2种是执行环境,它用于实际执行代码。执行二进制代码(运行.exe可执行程序)
二. 详解编译+链接
2.1 翻译环境
翻译就是将每个.c文件单独经过编译器编译,生成.obj目标文件,再将目标文件和库经过链接器链接,生成可执行程序.exe。
我们是可以找到这些文件的
vs2019 集成开发环境 集成了:编译器(cl.exe)+链接器(link.exe)+调试器
在vs2019这样的集成开发环境中不方便观察这些细节,这里我使用Linux系统,使用gcc这个编译器给大家演示一下整个过程
翻译的大概过程
编译分为预处理,编译,汇编,链接只有链接
预处理:主要做的是注释的删除,头文件的包含,符号的替换
编译:主要是将c语言代码进行拆解翻译成汇编指令,语法分析,词法分析,语义分析,符号汇总(关键)
汇编:将汇编代码翻译成二进制指令,并形成符号表
链接:1.合并段表(下边会讲段表)2符号表的合并和重定位
1. 预处理 选项 gcc -E test.c -o test.i预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。2. 编译 选项 gcc -S test.c编译完成之后就停下来,结果保存在test.s中。3. 汇编 gcc -c test.c汇编完成之后就停下来,结果保存在test.o中。
linux下gcc编译产生的目标文件test.o,可执行程序test都是按照ELF这种文件格式来存储的
段表可以理解为编译.c,.h文件的储存格式,下边就是段表
符号表的合并和重定位,大致是下边过程
编译阶段符号汇总(具有特殊意义的符号,最常见的是函数名),汇编阶段形成符号表并填充地址,链接阶段符号表合并且重定位(test.c形成的Add是无效地址,所以需要链接将符号表合并),合并段表(两个源文件就是两张段表)
以上就是翻译环境的介绍
2.2 运行环境
程序执行的过程:1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。2. 程序的执行便开始。接着便调用main函数。3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack)(函数栈帧),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。4. 终止程序。正常终止main函数;也有可能是意外终止。
三.预处理详解(这个模块会在后续更新,最近在期末考试,后续会补的)