操作系统,CPU,编译器,运行时库,系统调用的关系 之 编译器篇

来源:互联网 发布:数据采集卡的选择 编辑:程序博客网 时间:2024/05/16 14:06

操作系统,CPU,编译器,运行时库,系统调用。这是计算机科学中相对高大上的几个概念,许多科班出身的码农甚至也搞不清楚一个简单代码执行过程中,哪块是操作系统控制,哪块是编译器控制,CPU到底扮演了何种角色,什么是运行时库。

思考问题,我们首先要把握宏观,掌握好了大致情况,然后再对自己感兴趣的节点做深入分析。这是一种很实用的思考问题的方式,不会让你陷入“局部最优解”,更重要的是,它可以让你更深刻地理解问题的本质,遇到困难时不致迷茫。本文将梳理计算机科学中一些基本的概念,我们将沿着程序从出生到消亡的脉络,探讨CPU,探讨编译器,探讨操作系统和运行时库,以此来深入理解计算机系统。


编译器


         编译器绝对是计算机科学中殿堂级的领域,能够写编译器的都是大牛中的大牛,笔者依稀记得自己本科做编译原理大作业的情境,那4张8K的纸愣是没有画出一个简单语言的语法状态转移图。今天,我们不谈编译器原理,只关注其作用。编译器是高级语言到机器语言的转换器。当你洋洋洒洒地写完一万行代码时,那些struct、if、while除了你和C编译器看得懂外,没人能看得懂了,机器也不例外。机器只能看懂01码,编译器就是负责把源代码翻译成01码的。Windows下.exe后缀的程序就是一串01码,linux下你的a.out也是01码,但是01码绝对不止这些,linux下的.o和windows下的.dll也都是01码,只不过这些01码不能直接执行,而是由a.out和.exe程序调用。

         这就是编译器了,其实你只要记住它是高级语言到机器语言的转换器即可,这种工作在现实生活中叫:翻译。有了编译器,你的思想就结晶为01码了。

         没有这么简单,我们还要再深入一层。都知道程序包括代码数据,对于代码其实我们能有个感官的认识,这主要因为大家基本都学过汇编语言,代码汇编的层面基本都转化为mov,jmp,add等指令了,相信许多人也写过类似代码,但是数据呢?编译器如何“编译”数据

         你该鄙视我了:数据这东西怎么能“编译”呢?是的,数据确实不是编译的,你可以说它被编译器“安置”在一个位置上,但是对于数据的理解绝对不止此。首先全局变量和局部变量有着重大的差别,还有就是那些看似简单但是充满着智慧的基本数据类型(int,short,double等),还有就是老生常谈的字符串    

 

全局变量和局部变量


         最终的可执行文件以01码存储,这点已经确定。分析一个典型的可执行文件,以ELF文件(Linux下可执行文件)为例,发现最终的01码主要包括以下几个部分:静态数据区,代码区,字符串常量区等等。其中你的全局变量就是存放在ELF文件的静态数据区,代码就是存放在代码区,而像以如下方式声明的字符串“hello world1”则是存储在了字符串常量区:

                                                                                    char *str  ="hello world1";

         还有局部变量。记住,在可执行文件的01码当中,不会有局部变量的位置,这是因为局部变量是放到了程序的栈空间中。说到了栈,栈仅仅是在程序运行的时候才会有的概念,所以在编译器产生的01码中,不会有类似于“局部变量区”的分块。趁热打铁。以上我们解决了代码的安置、全局变量以及字符串的安置,那么局部变量是怎么安置的呢,它总不会无缘无故地就出现了吧。所谓的局部变量就是在函数内部定义的变量,比如以下函数:

                                                            int func{    int a;    char b[2];}

        其中,a和b都是局部变量,局部变量位于该函数的栈空间中。比如,当调用函数func时,程序的堆栈将会是如下的状态:


        由于栈是一个动态的结构,只有在程序执行的时候才会涉及,所以a和b变量肯定在是程序执行过程中产生的。所以已经不难理解了,每一个子函数汇编代码的初始部分肯定会有一个压栈的过程,上例中是压入1个int和2个char。子函数中的对a和b的引用都被关联到栈上的这块区域。所以,局部变量和全局变量有着本质的不同:全局变量在01码中就存在了,是静态的,而局部变量在01码中还仅仅是一些push变量,是动态的;全局变量将伴随整个程序执行过程,而局部变量生命期只是短短的子函数执行时间。


基本数据类型


       几乎所有C语言教科书的入门章节都是基本数据类型,在这里我们不谈那些强数据类型与弱数据类型的差别了,来点干货。为什么要说数据类型?源于我自己的一个疑惑。学计算机这几年中,每当遇到数据类型的问题,我耳边总是充斥着各种各样的声音:数据类型和编译器相关,数据类型和操作系统相关,数据类型和CPU相关,数据类型和平台相关。数据类型到底和什么相关?

         不妨挨个来分析。首先数据类型肯定和CPU相关,比如32位和64位CPU的sizeof(char*)返回值就不一样,说明由于CPU的不同数据的类型有很大的不同。和编译器肯定也是相关的,数据类型不但包括该类型所占内存的大小,还包括对于该种类型所施加的操作(这个定义和C++中的类很像,除了数据还应该有函数)。在数据类型的转换操作中,不同编译器的行为很是不一样。比如unsigned char类型强转long类型,有些编译器就可能会把long多出来的3个byte分别赋值为0xFF,而有些编译器则会将这3个byte赋值为0x00。这样,同一个操作在不同的编译器上产生了不同的行为与结果,而这些行为都是对应程序静态的01码的,所以数据类型与编译器也是相关的。对于操作系统,由于它也仅仅是一个程序而已,是一个“政府程序”,本身构建于CPU之上,所以不能说数据类型与操作系统相关。

         好,分析到这里,我基本上是得出了一个结论,那就是数据类型是和CPU、编译器相关,这就是某些人所谈到的平台。至于操作系统,我们姑且把它当作一个和普通程序无异的程序吧,只不过它手里握有资源。

         说到这里,编译器就说完了。是的,编译器用来产生01码,产生的过程中用到了各种智慧!在这个阶段,程序还是躺在硬盘上的一个代码,静静地等待执行。

0 0
原创粉丝点击