一.IL语言简述
IL语言是一个完整的面向对象语言,它是由所有.NET语言最小的共同部分组成的。所有.NET语言经过JIT编译后,形成接近于汇编的语言IL,应用程序在执行期间,通过CLR将IL编译成机器语言。
理论上,我们可以直接用IL语言开发程序,与用汇编语言开发类似,但IL语言比较繁琐,开发起项目比较费事。所以呢,我们还是用微软提供的开发环境(visual studio)编写高级语言(c#或vb.net或c++),难道说IL就没有用了吗?万物存在必有其存在的道理,IL也不例外。我们可以通过ILDSAM.EXE或Reflector工具分析程序集,从而可以理解程序是怎么运行的。
ILDSAM.EXE(反IL汇编器)在<visual studio安装目录下>"SDK"v2.0"Bin下找到,如ILDSAM.EXE在我的电脑上的路径是:C:"Program Files"Microsoft Visual Studio 8"SDK"v2.0"Bin。
二.IL语法
下面简单介绍下IL语法关键字的含义。
下面是简单的控制台程序,如下:运行ILDSAM,IL语言 如下:
和汇编语言类似,下面简单的说下各关键字的主要含义:
方法中的所有局部变量都在.locals标记的段落中以同样的方式声明。在声明所有的局部变理以后,程序的正文开始,每条IL指令的行开头都是以IL_XXXX标记开头。
LD:以ld开头的指令把变理从内存装载到堆栈,如下:
ldc—把一个数字常数装入堆栈, 如上ldc.i4.1,意思是将常数1作为4字节整数压入栈。
ldloc-把一个局部变量装入堆栈,如ldloc.1指将每1号局部变量的值压入栈的顶部。
Ldlarg-用于将一个函数参数的值加到栈顶。
ST:负责把一个条目存入内存
Stloc.N,指将栈顶的值弹出,存储到第N号局部变量中。
CALL和CALLVIRT指令调用其他方法和函数。CALL通常表示被调用的方法是静态的或共享的,而CALLVIRT则用于实例方法。就两种指令来说,方法的名字都会在指令中包括。被送到方法的任何参数都会被弹出堆栈而且要在方法被调用之前装载
基本的语法就说这么多吧,其他的关键字google一下就能找到许多。
三.程序分析
有人说,你用两个标题介绍IL,但还是没说学了IL能做什么啊。开发不用IL,那IL的用在哪里呢。下面我简要的说下IL的用途之一(当然也有其他作用,不是本文的重点,略过)。
以一个简单的例子来说IL的用途,代码如下(控制台程序):
程序测试一中,主要有三个类A,B,C,B继承A,C继承B,A类中有个虚方法Show,B类中,没有对Show方法进行 override,而是new了一个虚方法Show,C类中,override Show方法, 当主程序
A t = new C();
t.Show();
后,输出结果是什么呢。
测试二,将三个字符串分别存储到三个变量中,然后再连接起来,为什么总是提倡用StringBuilder连接字符串呢,看看IL后,你或许能知道原因。
测试三想考察是直接输出三个字符串的拼接,在内存中是如何操作的呢,还是看下IL
程序运行结果如下,
IL语言如下:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 代码大小 82 (0x52)
.maxstack 3
.locals init ([0] class test1.A t,
[1] string a,
[2] string b,
[3] string c,
[4] string test,
[5] class [mscorlib]System.Text.StringBuilder str)
IL_0000: nop
IL_0001: newobj instance void test1.C::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance void test1.A::Show()
IL_000d: nop
IL_000e: ldstr "a"
IL_0013: stloc.1
IL_0014: ldstr "b"
IL_0019: stloc.2
IL_001a: ldstr "c"
IL_001f: stloc.3
IL_0020: ldloc.1
IL_0021: ldloc.2
IL_0022: ldloc.3
IL_0023: call string [mscorlib]System.String::Concat(string,
string,
string)
IL_0028: stloc.s test
IL_002a: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
IL_002f: stloc.s str
IL_0031: ldloc.s str
IL_0033: ldstr "abc"
IL_0038: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_003d: pop
IL_003e: ldloc.s str
IL_0040: callvirt instance string [mscorlib]System.Object::ToString()
IL_0045: call void [mscorlib]System.Console::WriteLine(string)
IL_004a: nop
IL_004b: call string [mscorlib]System.Console::ReadLine()
IL_0050: pop
IL_0051: ret
} // end of method Program::Main
分析测试一:
Locals 程序首先声明变量,然后newobj C类 (对应 程序A t = new C();)
callvirt 调用A类的Show方法 (t.Show();)
为什么会是这样呢,主要还是考察类继承方面的知识,及虚方法,还有关键字new 、override 的含义。
测试二:其实没什么好说的,主要是载入字符串,再保存到变量,主要是保存三次,哦,对了,这个例子不是太好,应该先声明一个变量,然后用这个变量进行连接字符串,如
String test=”a”;
Test+=”b”;
Test+=”c”;
这样,再看下IL,补上,这段IL代码如下:
IL_0039: ldstr "a"
IL_003e: stloc.s test
IL_0040: ldloc.s test
IL_0042: ldstr "b"
IL_0047: call string [mscorlib]System.String::Concat(string,
string)
IL_004c: stloc.s test
IL_004e: ldloc.s test
IL_0050: ldstr "c"
IL_0055: call string [mscorlib]System.String::Concat(string,
string)
IL_005a: stloc.s test
IL_005c: ldstr bytearray (74 00 65 00 73 00 74 00 D8 53 CF 91 2B 00 3D 00 // t.e.s.t..S..+.=.
3A 00 ) // :.
IL_0061: ldloc.s test
IL_0063: call string [mscorlib]System.String::Concat(string,
总结:
本文简单介绍下IL的用法,当想了解.NET语言的是如何运行的,或者想分析性能,IL可以做为一个参考,当然,.NET语言的性能,得用其他的工具进行测试。
还有,园中有两位大牛对是否该学习掌握IL 而吵的不可开交,在备注中有他们的博文地址,感兴趣的朋友可以阅读一下,本人对是否学习IL 不做任何评说,一切都由你自己说了算。好了,就到这了。
microsoft.net_il语言程序设计.chm 英文文档,如果想收藏的话,请留下邮箱。当然也可以去网上下载。一切还是你自己说了算。
备注:
批驳小赵之IL无用论(1) http://www.cnblogs.com/Jax/archive/2009/06/02/1494167.html
关注底层:IL部分 http://www.cnblogs.com/yuyijq/archive/2009/06/02/1494324.html