前言
在ANSI C(标准C语言版本)的任何一种实现中,存在两种不同的环境,第一种是翻译环境,在这个环境中源代码被转化为可执行的机器指令,第二种是运行环境,用于实际执行代码。本篇文章就带大家了解这两种环境,帮助我们更好的理解程序是怎么运行起来的。
翻译环境
组成一个程序的每个源文件各自单独经过编译器处理处理后形成目标文件(.obj为后缀的文件),每个目标文件在由链接器链接,形成一个单一而完整的程序。同时链接器也会引入标准C库函数中任何被该程序使用的函数,并且还可以搜索程序员个人的程序库,请其中程序所需的函数也链接到程序中。
编译
在编译过程中,也分为3个阶段,分别是预处理(预编译)、编译、汇编
预处理
在预处理阶段进行的是文本操作,主要包括:
· 注释的删除
· #include头文件的包含
· #define符号的替换(所有的预处理指令都在预处理阶段处理)
之后便生成一个中间文件(filename.i)
例如以下代码:
#include<stdio.h>
#define B 7
int main(void)
{
int a=B+1//求B+1的和
printf("%d",a);
return 0;
}
在预处理阶段进行后,变为:
...
...(此处表示头文件stdio.h的内容)
int main(void)
{
int a=7+1;
printf("%d",a);
return 0;
}
同时将处理后的代码放到一个中间文件中
编译
该阶段主要进行语法分析、词法分析、语义分析、符号汇总(汇总的是全局对象),之后将C代码翻译成汇编指令,同时生成一个文件(filename.s)存放这些指令。这里的符号汇总和后面的形成符号表在后面会讲,这里先不管。
汇编
汇编阶段进行的是形成符号表,并将前面形成的汇编指令转换成二进制指令,放入生成的目标文件(filename.o / filename.obj)中,该文件是按ELF这种文件格式存储的(可以用readelf这个工具解读里面的二进制指令),这种格式会把文件划分为各种各样的段,如文本段、数据段等。
链接
在链接阶段,主要做了两件事:
①合并段表
前面说过,在汇编过程中目标文件被划分为各种各样的段,此时要将各个目标文件里面相同的段合并起来,最终合成到一个可执行程序里面(可执行程序也是按ELF这种格式存储)
将目标文件中的各种段进行合并
②符号表的合并和符号表的重定位
下面通过图片说明符号汇总–形成符号表–符号表的合并和符号表的重定位
因此在链接过程中如果没有找到某个符号或或者通过地址找不到该全局对象时就会出现链接错误。
运行环境
程序想要运行起来,执行过程如下:
①程序载入内存中
在有操作系统的环境中,这一般都是操作系统完成的,但在独立的环境中,程序的载入要手动操作,也可能是可执行代码置入只读内存来完成
②程序开始执行,开始调用main函数
③开始执行程序代码
程序将使用一个运行的堆栈(调用函数栈帧,我写过一篇关于函数栈帧的文章,感兴趣的可以去看看)
④终止程序
可能是正常终止main函数,也可能是异常终止
结语
以上就是本文关于程序的翻译环境和运行环境的所有内容,如果你觉得对你有帮助,不要忘记点赞收藏加关注哦,当然,如果本文有什么讲得不得当的地方,恳请指正,您的反馈将会铸就下一篇更加优质的文章。