说是翻译,都是抄代码,不说翻译吧,这东西也不是俺整的,将就着看吧
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),因此,约束变量作用域是编译器的任务。