在這之前,讓我說出Release和Debug編譯出的軟體的區別,我還真的只能說寫套話,沒有什麼深入的瞭解和實際的感觸。最近研究MSIL,在寫一段C#代碼出現了點手誤。就是這個失誤,透過MSIL,讓我從一個方面瞭解了二者的區別。
源碼如下:
int x, y, z;
string s;
Console.WriteLine("Enter x:");
s = Console.ReadLine();
x = Int32.Parse(s);
Console.WriteLine("Enter y:");
s = Console.ReadLine();
y = Int32.Parse(s);
if (x < y)
z = x;
else
z = y;
Console.WriteLine("{0:d}, z");
很容易看到,手誤在最後一行,我的本意是輸出z的值。由於引號的位置錯了,這樣的輸出就變成了:{0:d}, z。這樣if...else一段根本是沒用的。
Debug編譯出來的MSIL代碼是這樣的:
.method private hidebysig static void Main(string[] args) cil managed
...{
.entrypoint
// Code size 80 (0x50)
.maxstack 2
.locals init ([0] int32 x,
[1] int32 y,
[2] int32 z,
[3] string s,
[4] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr "Enter x:"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: call string [mscorlib]System.Console::ReadLine()
IL_0011: stloc.3
IL_0012: ldloc.3
IL_0013: call int32 [mscorlib]System.Int32::Parse(string)
IL_0018: stloc.0
IL_0019: ldstr "Enter y:"
IL_001e: call void [mscorlib]System.Console::WriteLine(string)
IL_0023: nop
IL_0024: call string [mscorlib]System.Console::ReadLine()
IL_0029: stloc.3
IL_002a: ldloc.3
IL_002b: call int32 [mscorlib]System.Int32::Parse(string)
IL_0030: stloc.1
IL_0031: ldloc.0
IL_0032: ldloc.1
IL_0033: clt
IL_0035: ldc.i4.0
IL_0036: ceq
IL_0038: stloc.s CS$4$0000
IL_003a: ldloc.s CS$4$0000
IL_003c: brtrue.s IL_0042
IL_003e: ldloc.0
IL_003f: stloc.2
IL_0040: br.s IL_0044
IL_0042: ldloc.1
IL_0043: stloc.2
IL_0044: ldstr "{0:d}, z"
IL_0049: call void [mscorlib]System.Console::WriteLine(string)
IL_004e: nop
IL_004f: ret
} // end of method Program::Main
Release編譯出來的就簡單多了,而且也沒有nop操作:
.method private hidebysig static void Main(string[] args) cil managed
...{
.entrypoint
// Code size 61 (0x3d)
.maxstack 2
.locals init ([0] int32 x,
[1] int32 y,
[2] string s)
IL_0000: ldstr "Enter x:"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: call string [mscorlib]System.Console::ReadLine()
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: call int32 [mscorlib]System.Int32::Parse(string)
IL_0016: stloc.0
IL_0017: ldstr "Enter y:"
IL_001c: call void [mscorlib]System.Console::WriteLine(string)
IL_0021: call string [mscorlib]System.Console::ReadLine()
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: call int32 [mscorlib]System.Int32::Parse(string)
IL_002d: stloc.1
IL_002e: ldloc.0
IL_002f: ldloc.1
IL_0030: pop
IL_0031: pop
IL_0032: ldstr "{0:d}, z"
IL_0037: call void [mscorlib]System.Console::WriteLine(string)
IL_003c: ret
} // end of method Program::Main
我一開始使用Release編譯的,感覺很奇怪,明顯if...else一段就沒有編譯。我想怪哉了。然後運行了一下,發現結果是“{0:d},z"。發現了最後一行的手誤,這一手誤直接導致if...else一段成了垃圾代碼。然後用F11單步跟蹤,if...else那段代碼根本就是整體跳過。於是換Debug模式編譯,發現編譯出來的MSIL的if...else是完整的,單步跟蹤也跟進去了。恍然大悟。。。