目前,我们都是采用高级语言编程(写汇编和机器语言的大牛们除外),但是计算机只能识别二进制(机器语言),不能直接理解高级语言,所以我们必须把高级语言“翻译”成计算机能够理解的机器语言。
说到“翻译“,其实总共有两种方式:
1. 编译:通过编译系统(不仅仅只是通过编译器,编译器只是编译系统的一部分)把高级语言“翻译”成机器语言(具体翻译过程可以参看下图),
把源高级程序编译成为机器语言文件,比如windows下的exe文件。
一个完整的编译系统与 一个用C编写的程序hello.c的编译过程
2. 解释:解释型程序在运行的时候才“翻译”,比如VB语言,在执行的时候,专门有一个解释器将VB语言“翻译”成机器语言,
每条语句都是执行的时候才翻译。
编译型与解释型,两者各有利弊:
1、 编译型语言:一次编译完成后,可以直接运行,程序执行效率高;
解释型语言:执行时才“翻译”成机器语言,解析一行,“翻译”一行,执行一行,程序执行效率相对较低;
但是不能一概而论,部分解释型语言的解释器通过在运行时动态优化代码,甚至能够使解释型语言的性能超过编译型语言。
2、由于编译型程序执行速度快,同等条件下对系统要求较低,因此像开发操作系统、大型应用程序、数据库系统等时都采用它,
像C/C++、Pascal/Object Pascal(Delphi)等都是编译语言;
而一些网页脚本、服务器脚本及辅助开发接口这样的对速度要求不高、对不同系统平台间的兼容性有一定要求的程序则通常使用解释性语言,
如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。
但随着硬件的升级和设计思想的变革,编译型和解释型语言越来越笼统,主要体现在一些新兴的高级语言上,而解释型语言的自身特点也使得
编译器厂商愿意花费更多成本 来优化解释器,解释型语言性能超过编译型语言也是必然的。
说到这里,我们有必要说一下java与C#:解释型语言和编译型语言的区别
JAVA语言是一种编译型-解释型语言,同时具备编译特性和解释特性(其实,确切的说java就是解释型语言,其所谓的编译过程只是将.java文件编程成平台无关的字节码.class文件,并不是向C一样编译成可执行的机器语言,在此请读者注意Java中所谓的“编译”和传统的“编译”的区别)。作为编译型语言,JAVA程序要被统一编译成字节码文件——文件后缀是.class。此种文件在java中又称为类文件。java类文件不能在计算机上直接执行,它需要被java虚拟机“翻译”成本地的机器码后才能执行,而java虚拟机的翻译过程则是解释性的。java字节码文件首先被加载到计算机内存中,然后读出一条指令,翻译一条指令,执行一条指令,该过程被称为java语言的解释执行,是由java虚拟机完成的。而在现实中,java开发工具JDK提供了两个很重要的命令来完成上面的编译和解释(翻译)过程。两个命令分别是java.exe和javac.exe,前者加载java类文件,并逐步对字节码文件进行编译,而另一个命令则对应了java语言的解释(javac.exe)过程。在次序上,java语言是要先进行编译,接着解释执行。
C#语言是编译型语言,但其“编译”过程比较特殊,具体说明如下: C#程序在第一次运行的时候,会依赖其.NET Frameworker平台,编译成IL中间码),然后由JIT compiler翻译成本地的机器码执行。从第二次在运行相同的程序,则不需要再执行以上编译和翻译过程,而是直接运行第一次翻译成的机器码。显然对于C#来说,通常第一次运行时间会很长,但从第二次开始,程序的执行时间会短很多。 那么,C#为什么要进行两次“编译”呢?其实,微软想通过动态编译(由JIT compiler工具实现)来实现其程序运行的最优化。如果代码在运行前进行动态编译运行,那么JIT compiler可以很智能的根据你本地机器的硬件条件来进行优化,比如使用更好的register,机器指令等等,而不是像原来那样,build一份程序针对所有硬件的机器跑,没有充分利用各个机器的条件。 另外,还有我们经常用到的脚本语言,比如JavaScript、Shell等语言都是脚本语言,本质上来说,脚本语言就是解释型语言。
编译型与解释型语言各有优缺点,一批新兴的语言有把两种类型进行折衷的趋势,例如Java语言虽然比较接近解释型语言的特征,但在执行之前已经预先进行一次预编译,生成的代码是介于机器码和Java源代码之间的中介代码(字节码),运行的时候则由JVM(Java的虚拟机平台,可视为解释器)解释执行。它既保留了源代码的高抽象、可移植的特点,又完成了对源代码的大部分预编译工作,因此执行起来比“纯解释型”程序要快许多。
而像VB6(或者以前版本)、C#这样的语言,虽然表面上看生成的是.exe可执行程序文件,但VB6编译之后实际生成的也是一种中介码,只不过编译器在前面安插了一段自动调用某个外部解释器的代码(该解释程序独立于用户编写的程序,存放于系统的某个DLL文件中,所有以VB6编译生成的可执行程序都要用到它),以解释执行实际的程序体。
C#(以及其它.net的语言编译器)则是生成.net目标代码,实际执行时则由.net解释系统(就像JVM一样,也是一个虚拟机平台)进行执行。虽然.net目标代码已经相当“低级”,比较接近机器语言了,但是仍将其视为编译语言,而且其可移植程度也没有Java号称的这么强大,Java号称是“一次编译,到处执行”,而.net则是“一次编码,到处编译”。呵呵,当然这些都是题外话了。总之,随着设计技术与硬件的不断发展,编译型与解释型两种方式的界限正在不断变得模糊。