编译引入中间语言优势
1. 编译型语言和解释型语言的区别
编译型语言在程序执行之前,有一个单独的编译过程,将程序翻译成机器语言就不用再进行翻译了。
解释型语言,是在运行的时候将程序翻译成机器语言,所以运行速度相对于编C/C++ 等都是编译型语言,而Java,C#等都是解释型语言。
虽然Java程序在运行之前也有一个编译过程,但是并不是将程序编译成机器语言,而是将它编译成字节码(可以理解为一个中间语言)。
在运行的时候,由JVM将字节码再翻译成机器语言。
注:脚本语言一般都有相应的脚本引擎来解释执行。 他们一般需要解释器才能运行。JAVASCRIPT,ASP,PHP,PERL,Nuva都是脚本语言。C/C++编译、链接后,可形成独立执行的exe文件。
编译型语言:
编译型语言最大的优势之一就是其执行速度。用C/C++编写的程序运行速度要比用Java编写的相同程序快30%-70%。
编译型程序比解释型程序消耗的内存更少。
不利的一面——编译器比解释器要难写得多。
编译器在调试程序时提供不了多少帮助——有多少次在你的c语言代码中遇到一个“空指针异常”时,需要花费好几个小时来明确错误到底在代码中的什么位置。
可执行的编译型代码要比相同的解释型代码大许多。例如,C/C++的.exe文件要比同样功能的Java的.class文件大很多。
编译型程序是面向特定平台的因而是平台依赖的。
编译型程序不支持代码中实现安全性——例如,一个编译型的程序可以访问内存的任何区域,并且可以对你的PC做它想做的任何事情(大部分病毒是使用编译型语言编写的)
由于松散的安全性和平台依赖性,编译型语言不太适合开发因特网或者基于Web的应用。
解释型语言提供了极佳的调试支持。一名Java程序员只需要几分钟就可以定位并修复一个“空指针异常”,因为Java运行环境不仅指明了异常的性质,而且给出了异常发生位置具体的行号和函数调用顺序(着名的堆栈跟踪信息)。这样的便利是编译型语言所无法提供的。
另一个优势是解释器比编译器容易实现
解释型语言最大的优势之一是其平台独立性
解释型语言也可以保证高度的安全性——这是互联网应用迫切需要的
中间语言代码的大小比编译型可执行代码小很多
平台独立性,以及严密的安全性是使解释型语言成为适合互联网和Web应用的理想语言的2个最重要的因素。
解释型语言存在一些严重的缺点。解释型应用占用更多的内存和CPU资源。这是由于,为了运行解释型语言编写的程序,相关的解释器必须首先运行。解释器是复杂的,智能的,大量消耗资源的程序并且它们会占用很多CPU周期和内存。
由于解释型应用的decode-fetch-execute(解码-抓取-执行)的周期,它们比编译型程序慢很多。
解释器也会做很多代码优化,运行时安全性检查;这些额外的步骤占用了更多的资源并进一步降低了应用的运行速度。
解释型语言:
2. .NET程序首先被编译成中间语言IL,IL经过再次编译后才生成机器码。这样做有什么好处
方便独立开发语言和虚拟机吧。
还有这样就可以兼容各种语言,生成相同的il。
3. C# 为什么要弄成中间代码
1、因为c语言也不能说真正的跨平台,只是这种语言比较低级,各个平台的实现相对一致。
c语言的东西下载时还是会分平台的,比如for linux, for windows, for Mac等,不同平台的编译器对c的解释都有差异,所以只能说跨平台容易一些。
2、按微软的规划,以后的应用程序要从网上付费下载来使用,这样就带来下载软件的安全与否的问题,而C#经编译后形成的是中间代码,不可以在本地机器上直接执行,必须经过CLR转换成本地代码后才能执行。
这样,中间码可以顺利通过防火墙,而且安全性又有CLR来保证。
4. 编译型语言和解释型语言各自的优缺点是什么
一、编译型语言
优点:运行速度快,代码效率高,编译后的程序不可修改,保密性较好。
缺点:代码需要经过编译方可运行,可移植性差,只能在兼容的操作系统上运行 。
二、解释型语言
优点:可移植性较好,只要有解释环境,可在不同的操作系统上运行。
缺点:运行需要解释环境,运行起来比编译的要慢,占用资源也要多一些,代码效率低,代码修改后就可运行,不需要编译过程。
(4)编译引入中间语言优势扩展阅读:
编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成 为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、Delphi等。而相对的,解释性语言编写的程序不进行预先编译,以文本方式存储程序代码。在发布程序时,看起来省了道编译工序。但是在运行程序的时候,解释性语言必须先解释再运行。
5. 什么是中间语言(IL)它的作用
IL是.NET框架中中间语言(Intermediate Language)的缩写。使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermedate Language)的代码。
使用中间语言的优点有两点,一是可以实现平台无关性,既与特定CPU无关;二是只要把.NET框架某种语言编译成IL代码,就实现.NET框架中语言之间的交互操作。(《C#程序设计及应用教程》(第2版),马骏 主编)
参考:http://ke..com/view/2278922.htm
6. 什么叫中间语言
中间语言MSIT
在.Net框架中,公共语言基础结构使用公共语言规范来绑定不同的语言。通过要求不同的语言至少要实现公共类型系统(CTS)包含在公共语言规范中的部分,公共语言基础结构允许不同的语言使用.Net框架。因此在.Net框架中,所有的语言(C#,VB.Net,Effil.Net等)最后都被转换为了一种通用语言:微软中间语言(MSIL)。
MSIL是将.Net代码转化为机器语言的一个中间过程。它是一种介于高级语言和基于Intel的汇编语言的伪汇编语言。当用户编译一个.Net程序时,编译器将源代码翻译成一组可以有效地转换为本机代码且独立于CPU 的指令。当执行这些指令时,实时(JIT)编译器将它们转化为CPU特定的代码。由于公共语言运行库支持多种实时编译器,因此同一段MSIL代码可以被不同的编译器实时编译并运行在不同的结构上。从理论上来说,MSIL将消除多年以来业界中不同语言之间的纷争。在.Net的世界中可能出现下面的情况:一部分代码可以用Effil实现,另一部分代码使用C#或VB完成的,但是最后这些代码都将被转换为中间语言。这给程序员提供了极大的灵活性,程序员可以选择自己熟悉的语言,并且再也不用为学习不断推出的新语言而烦恼了。
解密微软中间语言的系列文章将通过一些简单易懂的方式来揭示中间语言的复杂原理。这些原理通过详细的例子来阐述。在一些例子中同时给出了源代码和中间代码,通过比较源代码和中间代码,我们可以更好地理解编译器的局限性,指导我们编写出更好更快的代码。
微软中间语言概述 1.用中间语言编写的一个简单程序
让我们从经典的Hello World例子开始。首先在一个文本编辑器中输入以下的代码,并保存为HelloWorld.il:
.assembly HelloWorldIL {}
.method static void HelloWorld() {
.entrypoint
ldstr "Hello World."
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
在一个中间语言程序中,如果某一行以“.”开始,则代表这是一个传输给汇编工具的指令,该指令要求汇编工具执行某些操作,例如生成一个函数或类。而没有以“.”开始的行是中间语言的代码。在中间语言中方法通过汇编命令method来定义,汇编命令后跟方法的返回值、名称和参数。方法体被包含在{}中。例子中的ret代表该方法的结束。
一个中间语言文件可以包含很多函数,汇编工具没有办法分辨应该首先执行哪一个方法。在诸如C#或VB这一类高级语言中,程序的入口方法通常都有特定的名称,例如在C#中的public static void Main()。这就是上面的汇编工具发出错误提示的原因。在中间语言中,第一个被执行的方法被称为入口函数(EntryPoint Function)。为了告诉汇编工具HelloWorld是入口函数,我们需要在代码中增加一条汇编命令entrypoint,该命令可以放在方法体中的任何位置。需要注意的是在一个程序集中只能有一个入口函数。
中间语言代码通常被编译成一个模块,该模块隶属于一个程序集。在.Net中模块和程序集的概念非常重要,因此开发人员需要很清楚地了解它们。在后面的文章中我们将详细讨论.Net程序的结构。通过在代码中加入assembly命令,可以告诉汇编工具中间代码隶属于那个程序集。assembly命令的格式如下:
.assembly <程序集名称> {}
需要注意在method命令后加入了static关键字,这是因为每个入口函数必须是静态的,例如在C#中我们将Main方法定义为public static void Main()。
接下来我们需要调用WriteLine方法将HelloWorld字符串输出到屏幕。通过使用call指令(Instruction)我们可以达到这个目的。指令的格式如下:
call <return type> <namespace>.<class name>::<method name>
这里我们可以看到当调用一个方法时,中间语言和其他的编程语言有很大的区别。在中间语言中,如果需要调用一个方法,需要指定方法的全名,包括他的名称域(namespace)、类名、返回值类型和参数的数据类型。这样就保证了汇编工具能够找到正确的方法。
在调用WriteLine方法时需要一个字符串参数。所有传递给方法或函数的参数都被保存在内存的堆栈中。在中间语言中有一个指令ldstr可以从堆栈中加载一个字符串。(堆栈是内存中的一块区域,它被用于将参数传输给方法,在后面我们会详细讨论堆栈的问题)。所有的方法都从堆栈中获取它们的参数,因此ldstr指令是必不可少的。ldstr指令的格式如下所示:
ldstr <parameter string>
我们可以用ILAsm.exe来编译这个程序。在运行ILAsm.exe之前,首先需要确认一下该程序已经包含在了Windows操作系统的Path环境变量中。ILAsm.exe 可在下面的路径中找到:
%windir%\Microsoft.NET\Framework\v1.0.xxxx
其中xxxx是正在使用的.NET框架的内部版本号。例如我使用的版本号是3705,则应该如下设置Path环境变量:
Set Path = %Path%;c:\Windows\Microsoft.NET\Framework\v1.0.3705
然后运行cmd.exe(开始->运行->输入cmd->按下确认键)。在弹出的命令窗口中输入:
J:\Testcode>ilasm HelloWorld.il
汇编代码后运行程序就可以看到Hello World.的输出。
通过上面的例子,我们了解了中间语言的程序结构,一些命令和指令。同时需要提醒大家的是中间语言是区分大小写的。
2.改进的HelloWorld例子
在.Net中的所有语言都是面向对象的语言,但是上面的HelloWorld例子是一个结构化的例子。下面让我们来看一下如何将它转化为面向对象的代码。在面向对象的编程中,我们将操作定义在类中。为了将上面的HelloWorld例子转化为面向对象的代码,可以使用class命令:
.class HelloWorld { }
class命令后紧跟的是类的名称。类的名称在中间语言中是可选的。同时我们还需要为该指令添加一些属性,例如存取控制类在内存中的布局和互用性等。这样代码就变成了:
.assembly HelloWorldIL {}
.class public auto ansi HelloWorld extends [mscorlib]System.Object {
.method public hidebysig static void HelloWorld() cil managed {
.entrypoint
ldstr "Hello World."
call void [mscorlib]System.Console::WriteLine(class System.String)
ret
}
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed {
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}
在代码中用到了三个属性:
· public:public是访问控制属性,它表明了对于访问该类的成员没有限制。
· auto:auto属性表明了当类被加载到内存中时,在内存中的布局是由公共运行库而不是程序决定的。
· ansi:指定ansi属性是为了在没有被管理和被管理的代码之间实现无缝的转化。在.Net中,那些不可直接应用在公共语言基础设施之上的代码被称为没有被管理的代码,例如C、C++和VB6的代码。我们需要一个属性来处理被管理的代码和没有被管理的代码之间的互用性。在被管理的代码中,字符串用双字节的Unicode字符表示,而在被管理的代码中,字符串有可能用单字节的ANSI字符表示。指定了ansi属性就可以在不同的代码间转化字符串了。
我们知道在.Net框架中,所有的类都直接或间接地继承了System.Object类。在代码中我们明确指定了HelloWorld继承了System.Object。
在HelloWorld方法中加入了public、hidebysig、cil managed属性,下面是对这些属性的解释:
· public:在C#或VB.Net中,当我们定义一个方法时,需要指定方法的访问修饰符。访问修饰符可以是public、protected、internal或private 。
· hidebysig:一个类可以继承其他的类,hidebysig属性保证当前类中的方法在作为父类时不会被子类继承。例如如果HelloWorldChild类继承了HelloWorld类,在HelloWorldChild中不会看到HelloWorld方法。
· cil managed:该属性将在后面讨论。
在高级语言中(C#,VB.Net等),每个类必须有构造函数,而且构造函数的第一行需要调用基类的构造函数。如果类中没有构造函数,基类的构造函数将被自动调用。通常这是由编译器自动完成的,现在我们要在的代码中加入构造函数,该构造函数通过.ctor命令调用基类的构造函数。
小结
本文我们从经典的Hello World例子开始,通过实例了解了微软中间语言的基本语法规则以及中间语言与其他开发语言的关系。在下一篇文章中,我们将在此基础上,运用实例程序讲述.net应用程序的格式和结构等内容。
7. 简述什么是源语言,目标语言,中间语言
源语言是外语翻译专业术语,和目标语相对。 源语言(可以引导出另一种语言的语言。在最初编写计算机程序时所使用的语言,就是源语言。源语言一般指的是,编写源程序所用的语言,它必须翻译成机器语言*才能在计算机中使用。) 目标语言:目标语 中间语言:独立于任何特定自然语言的中介表达式,能够统摄机器翻译所需的句法和语义信息,在机器翻译系统中表示源语和目标语之间的联系。
8. 一个典型的编译程序通常由哪些部分组成
1、词法分析
词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。执行词法分析的程序称为词法分析程序或扫描器。
2、语法分析
编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。
3、中间代码生成
中间代码是源程序的一种内部表示,或称中间语言。中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现。中间代码即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。
4、代码优化
代码优化是指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。所谓等价,是指不改变程序的运行结果。所谓有效,主要指目标代码运行时间较短,以及占用的存储空间较小。这种变换称为优化。
5、目标代码生成
目标代码生成是编译的最后一个阶段。目标代码生成器把语法分析后或优化后的中间代码变换成目标代码。
(8)编译引入中间语言优势扩展阅读:
编译程序把用高级程序设计语言书写的源程序,翻译成等价的机器语言格式目标程序的翻译程序。编译程序属于采用生成性实现途径实现的翻译程序。它以高级程序设计语言书写的源程序作为输入,而以汇编语言或机器语言表示的目标程序作为输出。
编译出的目标程序通常还要经历运行阶段,以便在运行程序的支持下运行,加工初始数据,算出所需的计算结果。
编译程序的实现算法较为复杂。这是因为它所翻译的语句与目标语言的指令不是一一对应关系,而是一多对应关系;同时也因为它要处理递归调用、动态存储分配、多种数据类型,以及语句间的紧密依赖关系。
但是,由于高级程序设计语言书写的程序具有易读、易移植和表达能力强等特点,编译程序广泛地用于翻译规模较大、复杂性较高、且需要高效运行的高级语言书写的源程序。
9. 编译过程中,源程序为什么要通过中间代码生成目标程序
源程序是指程序员编写的代码,可以被编译程序编译为目标程序。
如果是c++,那么后缀为.cpp
目标程序是编译程序将源程序编译后的结果,如果是c++,那么后缀是.o
编译程序一般是编译器公司(比如微软
intel他们都生产编译器)做的,它将源代码转化为机器可识别的文件,经过链接,生成可执行程序。
解释程序即解释器,它不需要经过编译阶段即可根据用户源程序执行。
程序语言分编译类和解释类语言。