就像我标题写的那样,是浅说。其实真的不是浅说,而是说的不是C语言,只是和C语言有一定的关系罢了。一直以来都觉得C语言好像是万能的,也许也是因为自己的C语言水平有限,也提不出来什么问题来表达自己的那种懵懂。现在看来,C语言就是如同我们的数学符号一样,都是为了表达和解决问题而生的,就像如果你连数学符号的1,2,3,4.。。。都不认识,那你怎么来做加减法的运算那样。所以符号其实代表了一种规则,一种可以因为有问题需要去解决才会产生的方法。
好了,还是从C语言说起吧,我们学习C语言,可以认为是在学习一种C语言编译器的规则,同时去学习用这个规则去解决问题的方法和方式。但有了这个编译器就可以了吗? 不,这还是不够的。这里有几个概念我就说下: C编译器,可执行程序,链接器,加载器。我们的目标就是为了能得到一个可执行程序,这也是我们最终的目标吧。可执行程序是什么,是根据我们写的程序通过编译、链接和加载,从而可以让我们的CPU能认识而去执行,执行的结果就是我们编程的目的。这样就是我们欢喜了,机器也欢喜了,皆大欢喜。可是你明白这样的过程是怎么来的吗?! 如果你明白那就不用再往下看了,没必要浪费你的时间了。
总体目的:为了得到可执行程序。 可执行程序是什么? 当一个程序编译完成时,就可以理解为一个程序了,但它并非可执行。为什么呢? 因为这个可执行的意思就可以让你的CPU去执行了,而CPU的执行是通过具体的物理地址和数据操作才有去执行的可能。这样就是有了个概念:物理地址固化,简单点就是将这个编译好的程序放在合适的cpu物理地址范围中,这样就才有被执行的可能。为了能达成这个目的: 现在的我们就有了三个步骤来完成这样,而使你的代码变成真正的可执行程序。这个步骤就是编译、链接、和加载。 而我们一直都在强调编译器,而去忽略链接和加载。从实现上来说,链接和加载真的是一闪而过,几乎和我们半毛钱的关系都没有。这样就会造成我以前一直遇到过的懵懂状态那样,只知道应该要这样做,而不知道为什么要这样做,真的很懵懂啊。接下来就从这三个方面来浅说下这个过程:
过程一:编译阶段,这个阶段就是将你的“高级”C语言编译成机器可以理解的指令,这样子就是我编程,我编程,我不停的编程,将自己要实现的东西,都自己编程好了。就放在一个大文件中,这样也了,可是你会发现这样的方法太累了,都需要自己去编程。有人就说了,不是有库吗?! 是啊,是有库,可以让我们避免这样的重复劳动,有个包含和链接就可以了,这样真的太方便了,我们只需要编写库中没有的,库中有的我们直接调用就可以了。那如何实现这样的调用呢? 于是就有了链接器。
过程二:链接阶段,就是为了让资源共享减少你的重复劳动,哪怕你是不停拷贝、黏贴;拷贝、黏贴,这也是个累人的活,而因为这样形成的大文件会造成查找BUG的不方便。链接就是将你编程中需要的共享资源都提取出来,通过“链接”的方式形成一个大文件。这个大文件中已包含了你这次编程所需要的一切逻辑资源。那这个是不是已是可执行程序了吗?! 当然不是,只是一个相对位置都固定的逻辑地址的程序体。而可执行就需要这个程序体的固化地址过程,这样就有了第三个阶段:加载器。加载器就是将你的程序从一个物理地址(你指定或按照架构的规定)开始依次固化整个文件,就像就数据写入到对应的地址那样,对应的地址就是物理地址,这就是“固化”。这样当我们的CPU开始从这个地址工作时,就是在运行这个程序了。
过程三:加载阶段,加载就是整个程序体的从相对地址到绝对物理地址对应过程,依次写入,就是“固化”的意思。
以上就是一个程序体如何被执行的一个基本流程和思路。当然什么优化之类的都包含在这三个过程中,所以说,学习C语言其实就是在学习一种C编译器,好在C语言已有自己的标准,让各种各样的C编译器遵循实现C语言的体系标准,都是为了达成生产可执行程序的目的。为了更好解决和拓宽这个C语言解决问题的能力,就一直不断的加强C编译器的功能,以达成人类世界和cpu这个机器世界的交流,更好的为我们服务。同时,也可以理解为C语言提供的是一种方**。
以上我的这些也是我在学生时代一直的困惑和懵懂,也许你也应该多问几个这样的“为什么会这样”,我们的先辈们真的是太有才了,这样可以让我们站在巨人的肩膀上谋取更大的胜利。
以此浅说来,鼓励要“知其然,而所以然“的同志们,也同时来回答下因为这个问题给我留言的同志朋友们。 |