编译器、虚拟机、操作系统,哪个更难?其实除了MATLAB之类的数学软件,比较难的一定是编译器了!虚拟机和操作系统与其说是辛苦,不如说是麻烦和大量工作。1、什么是虚拟机?可以运行字节码的程序就是虚拟机。CPU的机器码是字节码的一种,直接在硬件上运行,其运行由硬件的数字电路保证。但虚拟机是保证字节码运行的软件程序。软件程序是用高级语言编写的,可以写出非常高级的逻辑,实现起来比数字电路要简单得多。在字节码(机器码)层面,逻辑非常简单,远没有高级语言的源代码那么复杂。让字节码运行其实比编译器生成字节码更简单:因为生成字节码就是编码,让字节码运行就是解码,编码在任何时候都比解码复杂。编码需要将杂乱的信息组织有序。解码时,只需要依次读取有序信息即可。所以H264编码的CPU消耗远大于H264解码!如果字节码类似于RISC架构(如ARM)的机器码,那么每4个字节就是一条指令,指令中每一位的作用是固定的。所以,虚拟机的代码是这样的:uint32_tcodes[N];//程序的字节码数组for(i=0;i>25;//最高7位为操作码,可支持128条指令uint8_tsrc=(codes[i]>>19)&0x3f;//接下来的6位是源操作数的寄存器号,uint8_tdst=(codes[i]>>13)&0x3f;//接下来的6位是目的操作数的寄存器号,//寄存器号占6位,可以支持64个寄存器uint8_tflag=(codes[i]>>12)&0x1;//是否设置跳转标志,uint16_timm=codes[i]&0xfff;//可以携带12位立即数,run(ctx,opcode,src,dst,flag,imm);//运行字节码,ctx是进程上下文}这个程序难吗?不难。机器码的逻辑极其简单,比高级语言代码简单多了!特别是RISC体系结构比x64机器代码更简单。因为x64的机器码长度不固定,需要逐字节分析解释,稍微复杂一点,但复杂度远不及高级语言的源码!qemu比较复杂,因为它要模拟多种型号的CPU。为字节码实现一个跨平台的虚拟机并不难。将java源代码转成字节码的过程要比让java字节码运行起来困难得多:前者是编译器,后者是虚拟机。2.如果操作系统只是让OS内核运行在CPU上,大约只需要5000-8000行C代码!Linux0.01版本(第一个Linux版本)的代码量只有8000行左右。Linux0.11版本,大约不到20,000行。与编译器相比,操作系统只是麻烦多了而已!因为要支持的驱动模块多,要支持的文件系统多,要支持的网络协议多,这些模块的代码工作量大不过,麻烦不代表难!一个8000行代码的OS内核(比如Linux0.01)只需要实现进程管理、内存管理、控制台管理、键盘驱动、硬盘驱动,支持一个简单的文件系统就可以运行。这样的OSkernel其实已经很完整了。剩下的就是在文件系统下添加驱动模块和网络协议模块。根据Unix“一切皆文件”的设计理念,外围驱动模块和TCP/IP协议都是文件系统的子模块。shell(命令解释器)不属于OS内核,而是一个用来解释命令的用户态程序。当然,为了系统的使用,shell是必不可少的。基于文件系统的API,实现列出目录、创建目录、创建文件等功能并不难。当然,执行这些命令的工作量要大于运行一个8000行的OS内核。3、编译器单次语法分析可能超过10000行!如果语法像C++那么复杂,解析的代码量就更大。(如果使用第三方正则表达式库,第三方库的代码不少于10000行)并且在编译器的实现上有一些非常尴尬的地方,比如C++中的如下代码:vector<矢量>vecA;矢量<矢量>vecA;两个>>之间必须有一个空格,否则g++会报错。原因是键盘上的符号太少,C++的语法太复杂,无法应付编码。此外,编译器的后端还有一些非常复杂的模块,比如:指针分析、自动内存管理、循环分析、寄存器分配、goto处理等等。还有一个并行分析:for(i=0;i