操作系统,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码,产生的过程中用到了各种智慧!在这个阶段,程序还是躺在硬盘上的一个代码,静静地等待执行。
- 操作系统,CPU,编译器,运行时库,系统调用的关系 之 编译器篇
- 编译器,CPU和操作系统的宏
- CPU位数、操作系统位数和编译器位数关系
- CPU位数、操作系统位数和编译器位数关系
- CPU位数、操作系统位数和编译器位数关系
- CPU位数、操作系统位数和编译器位数关系
- VC++编译器背后的故事:编译、链接、运行、库、操作系统
- CPU,OS,编译器位数关系
- 编译器、操作系统、CPU相关的预处理宏定义
- 32位与64位 CPU、编译器、操作系统、应用程序、arm和X86关系
- 编译器系统之链接
- JIT编译器与CLR(共公语言运行库)的关系
- 编译器链接选项中运行时库的区别
- 调用时编译器的优化问题
- 32位与64位 CPU、编译器、操作系统与应用程序的区别
- .NET软件运行架构 之 打破编译器的界限
- 编译器的尾调用优化
- 编译器一:程序设计语言、编译器和开发环境之间的关系
- 设计模式六大原则(4):接口隔离原则
- 疯狂的猴子1
- at91_sdcard源码分析(3)
- 疯狂的猴子2
- Cocos2D-x游戏开发之五:CCControlPotentiometer and CCControlSlider
- 操作系统,CPU,编译器,运行时库,系统调用的关系 之 编译器篇
- hdwiki中lib文件目录功能
- OD对按钮下断点的方法
- dwr3与struts2整合,实现服务器端推送技术,实现多人聊天功能
- JAVA多线程基础
- 【黑马程序员】Objective-C语言学习笔记之对象的创建、使用和方法调用(三)
- java设计模式(行为型)之访问者模式
- MySQL导入.sql文件及常用命令
- Problem accessing /nn_browsedfscontent.jsp