随笔- 7  文章- 0  评论- 16 

说是翻译,都是抄代码,不说翻译吧,这东西也不是俺整的,将就着看吧

IL中,后面跟着冒号的称为’标签‘(就是一条IL指令的记号),用来做IL指令的无条件跳转,例子:

.assembly extern mscorlib{}

.assembly iltest {}

.class test{

.method public hidebysig static void  bbb() il managed

{

.entrypoint

ldstr "Hello,World!"

call void [mscorlib]System.Console::WriteLine(string)

haha:ldstr "HaHa"

call void [mscorlib]System.Console::WriteLine(string)

ret

}

}

 Haha就是一个标签,上例中输出是:

Hello,World!

HaHa

如果修改成:

.entrypoint

br haha

ldstr "Hello,World!"

call void [mscorlib]System.Console::WriteLine(string)

haha:ldstr "HaHa"

call void [mscorlib]System.Console::WriteLine(string)

蓝色指令br haha,表示程序无条件跳转到标记为haha的指令ldstr "HaHa",因此ldstr "Hello,World!"  call void [mscorlib]System.Console::WriteLine(string)两条指令就被跳过了,程序的输出为:haha  

Il中很多指令都有‘长、短’形式,比如上面的br就是长形式,占4字节,而br.s是短形式,占1字节

跳转指令br是IL中相当重要的指令

a.cs

class zzz

{

static bool i = true;

public static void Main()

{

if (i)

System.Console.WriteLine("hi");

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends System.Object

{

.field private static bool i

.method public hidebysig static void vijay() il managed

{

.entrypoint

ldsfld     bool zzz::i     将zzz:i的值1入栈

brfalse.s  IL_0011        如果为假(0),跳到IL_0011,为真(1)则继续执行

ldstr      "hi"           "hi"入栈(其实是"hi"的地址入栈--string是引用类型)

call       void [mscorlib]System.Console::WriteLine(class System.String)  打印输出

IL_0011: ret  返回

}

.method public hidebysig specialname rtspecialname static void .cctor() il managed

{

ldc.i4.1                   常量1入栈

stsfld     bool zzz::i       静态字段初始化

ret

}

}

Output

hi

C#例子都很简单,就不解释了。

   静态字段,在静态构造函数里初始化,如上例所示

   局部变量,在变量所在的方法里初始化

注意IL代码中的静态构造函数.cctor里的红色两行------对应于C#中的true和false,IL中并没有true和false值对应的专有符号(虽然有true和false类型),而是如上例所示:1代表true;0代表false。

由上可见:C#中的IF语句是通过IL中的跳转指令实现的,那IF ELSE 呢:

a.cs

class zzz

{

static bool i = true;

public static void Main()

{

if (i)

System.Console.WriteLine("hi");

else

System.Console.WriteLine("false");

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends System.Object

{

.field private static bool i

.method public hidebysig static void vijay() il managed

{

.entrypoint

ldsfld bool zzz::i

brfalse.s  IL_0013

ldstr  "hi"

call void [mscorlib]System.Console::WriteLine(class System.String)

br.s IL_001d

IL_0013:  ldstr      "false"

call void [mscorlib]System.Console::WriteLine(class System.String)

IL_001d: ret

}

.method public hidebysig specialname rtspecialname static void .cctor() il managed

{

ldc.i4.1

stsfld     bool zzz::i

ret

}

}

Output

hi 

很简单,就不解释了,就是把跳转的地方变了,第一个例子是跳转到ret(直接退出),这个例子跳转到对应于C#中else后面的语句,上例中的蓝色两行是实现的关键。

a.cs

class zzz

{

public static void Main()

{

}

void abc( bool a)

{

if (a)

{

int i = 0;

}

if ( a)

{

int i = 3;

}

}

}

a.il

.assembly mukhi {}

.class public auto ansi zzz extends [mscorlib]System.Object

{

.field private int32 x

.method public hidebysig static void vijay() il managed

{

.entrypoint

ret

}

.method private hidebysig instance void abc(bool a) il managed

{

.locals (int32 V_0,int32 V_1)

ldarg.1

brfalse.s  IL_0005

ldc.i4.0

stloc.0

IL_0005:  ldarg.1

brfalse.s  IL_000a

ldc.i4.3

stloc.1

IL_000a:  ret

}

}

上例体现了C#和IL中变量作用域的不同,C#中,两个i分别在各自的{}里有效,所以即使名称相同,却不冲突。IL中,两个i变成了两个独立的变量(V_0,V_1),名称不同,且两个变量的作用域相同-----都是整个方法体,可见:变量冲突是由编译器负责检查的,IL中,变量都有不同的名字,不存在冲突,且变量的作用域都是整个方法。

 C#中的WHILE循环:

a.cs

class zzz

{

static bool i = true;

public static void Main()

{

while (i)

{

System.Console.WriteLine("hi");

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends System.Object

{

.field private static bool i

.method public hidebysig static void vijay() il managed

{

.entrypoint

br.s IL_000c           跳到条件判断

IL_0002:  ldstr      "hi"

call void [mscorlib]System.Console::WriteLine(class System.String)

IL_000c: ldsfld     bool zzz::i

brtrue.s  IL_0002      当栈上是1就跳,是0就不跳

ret

}

.method public hidebysig specialname rtspecialname static void .cctor() il managed

{

ldc.i4.1

stsfld     bool zzz::i

ret

}

}

上例的IL,如C#中的while先要判断条件一样,先跳到判断条件的地方,如果条件满足,就跳到while执行体中,如果不满足,就跳出while,跳来跳去,IL就把C#中的while循环搞定了(C#中的循环与分支都让IL这么跳啊跳给解决的)。明显上面是个死循环,跳不出去了-_-!!

a.cs

class zzz

{

static int i = 2;

public static void Main()

{

i = i + 3;

System.Console.WriteLine(i);

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends System.Object

{

.field private static int32 i

.method public hidebysig static void vijay() il managed

{

.entrypoint

ldsfld int32 zzz::i      i入栈

ldc.i4.3              3入栈

Add                 把i 3取出来(出栈),相加,把结果压栈

stsfld int32 zzz::i       结果出栈,存入i

ldsfld int32 zzz::i       i入栈

call void [mscorlib]System.Console::WriteLine(int32)

ret

}

.method public hidebysig specialname rtspecialname static void .cctor() il managed

{

ldc.i4.2

stsfld     bool zzz::i

ret

}

}

Output

5

上例演示了IL中的加法(四则运算以后就不用逐一介绍了吧)

补充一下:i++也就是让i add 1 实现的

不等运算:(不帖整个的代码了 太长 太罗嗦)

C# :   bool i = 5>6;

IL:

Ldc.i4 5

Ldc.i4 6

cgt

由上可得:> 对应IL指令 cgt    ( >对应 cgt  < 对应clt   = = 对应 ceq  )

>= 没有cgtoreq这个指令 呵呵

>=就是不<, 5>=6 就是把5<6的结果取返:

Ldc.i4 5

Ldc.i4 6

Clt

Ldc.i4 0

Ceq 

以此同理:

!= 就是= =取返

5 != 6

Ldc.i4 5

Ldc.i4 6

Ceq 

Ldc.i4 0

Ceq 

看下不是死循环的while循环

a.cs

class zzz

{

static int i = 1;

public static void Main()

{

while ( i <= 2)

{

System.Console.WriteLine(i);

i++;

}

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends System.Object

{

.field private static int32 i

.method public hidebysig static void vijay() il managed

{

.entrypoint

br.s IL_0018

IL_0002:  ldsfld     int32 zzz::i

call void [mscorlib]System.Console::WriteLine(int32)

ldsfld int32 zzz::i

ldc.i4.1

add

stsfld int32 zzz::i

IL_0018:  ldsfld int32 zzz::i

ldc.i4.2

ble.s IL_0002

ret

}

.method public hidebysig specialname rtspecialname static void .cctor() il managed

{

ldc.i4.s   1

stsfld int32 zzz::i

ret

}

}

Output

1

2

上来红色跳到条件判断(黄色),如果为真就跳到循环体(红色),红色完了到黄色(继续判断),知道为假退出循环。

ble.s IL_0002这个ble(相当于cgt加brfalse)值得关注,上面比较的时候也没见cltoreq  -_-!!,现在跳转出了ble(break when less than or equal),同理。。。

C#中的FOR循环:

a.cs

class zzz

{

static int i = 1;

public static void Main()

{

for ( i = 1; i <= 2 ; i++)

{

System.Console.WriteLine(i);

}

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends System.Object

{

.field private static int32 i

.method public hidebysig static void vijay() il managed

{

.entrypoint

ldc.i4.1

stsfld     int32 zzz::i

br.s       IL_001e

IL_0008:  ldsfld     int32 zzz::i

call       void [mscorlib]System.Console::WriteLine(int32)

ldsfld     int32 zzz::i

ldc.i4.1

add

stsfld int32 zzz::i

IL_001e:  ldsfld     int32 zzz::i

ldc.i4.2

ble.s IL_0008

ret

}

.method public hidebysig specialname rtspecialname static void .cctor() il managed

{

ldc.i4.s   1

stsfld int32 zzz::i

ret

}

}

Output

1

2

C#中WHILE循环与DO循环的比较,仔细观察IL中DO循环至少执行一次的实现方式:

a.cs

public class zzz

{

public static void Main()

{

int i;

i = 1;

while ( i <= 2)

{

System.Console.Write(i);

i++;

}

i = 1;

do

{

System.Console.Write(i);

i++;

} while ( i <= 2);

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void  vijay() il managed {

.entrypoint

.locals (int32 V_0)

ldc.i4.1

stloc.0

br.s       IL_000e

IL_0004:  ldloc.0

call       void [mscorlib]System.Console::Write(int32)

ldloc.0

ldc.i4.1

add

stloc.0

IL_000e:  ldloc.0

ldc.i4.2

ble.s      IL_0004

ldc.i4.1

stloc.0

IL_0014:  ldloc.0

call       void [mscorlib]System.Console::Write(int32)

ldloc.0

ldc.i4.1

add

stloc.0

ldloc.0

ldc.i4.2

ble.s      IL_0014

ret

}

}

Output

1212

C#中BREAK:

a.cs

public class zzz

{

public static void Main() {

int i ;

for ( i = 1; i<= 10 ; i++)

{

if ( i == 2)

break;

System.Console.WriteLine(i);

}

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void  vijay() il managed

{

.entrypoint

.locals (int32 V_0)

ldc.i4.1

stloc.0

br.s       IL_0014

IL_0004:  ldloc.0

ldc.i4.2

bne.un.s   IL_000a

br.s       IL_0019

IL_000a:  ldloc.0

call       void [mscorlib]System.Console::WriteLine(int32)

ldloc.0

ldc.i4.1

add

stloc.0

IL_0014:  ldloc.0

ldc.i4.s   10

ble.s      IL_0004

IL_0019:  ret

}

}

Output

1

红色两行是关键;bne------break when not equal

C#中的CONTINUE:

a.cs

public class zzz

{

public static void Main()

{

int i ;

for ( i = 1; i<= 10 ; i++)

{

if ( i == 2)

continue;

System.Console.WriteLine(i);

}

}

}

 

a.il

.assembly mukhi {}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void  vijay() il managed

{

.entrypoint

.locals (int32 V_0)

ldc.i4.1

stloc.0

br.s       IL_0014

IL_0004:  ldloc.0

ldc.i4.2

bne.un.s   IL_000a

br.s       IL_0010

IL_000a:  ldloc.0

call       void [mscorlib]System.Console::WriteLine(int32)

IL_0010:  ldloc.0

ldc.i4.1

add

stloc.0

IL_0014:  ldloc.0

ldc.i4.s   10

ble.s      IL_0004

ret

}

}

Break和continue的区别就在跳转的位置,break的是跳出循环,continue的是跳到循环变量自增那(结束当此循环)。

最后看看GOTO:

a.cs

public class zzz {

public static void Main()

{

goto aa;

aa: ;

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void  vijay() il managed

{

.entrypoint

br.s       IL_0002

IL_0002:  ret

}

}

变量的作用域:

a.cs

public class zzz

{

public static void Main()

{

int j;

for ( int i = 1; i <= 2 ; i++)

System.Console.Write(i);

}

}

a.il

.assembly mukhi {}

.class private auto ansi zzz extends [mscorlib]System.Object

{

.method public hidebysig static void  vijay() il managed

{

.entrypoint

.locals (int32 V_0,int32 V_1)

ldc.i4.1

stloc.1

br.s       IL_000e

IL_0004:  ldloc.1

call       void [mscorlib]System.Console::Write(int32)

ldloc.1

ldc.i4.1

add

stloc.1

IL_000e:  ldloc.1

ldc.i4.2

ble.s      IL_0004

ret

}

}

Output

12

C#代码里:在函数Main里创建变量j,在for循环里创建变量i,变量i的作用域是for循环,而j的作用域是整个Main方法

而在IL中:

所有变量(i j)都有相同的作用域(整个Main),因此,约束变量作用域是编译器的任务。


 posted on 2008-09-25 16:24 红泥 阅读(...) 评论(...) 编辑 收藏