2
当我试图了解回合实际上做我最后看一个简单的控制台程序(从C#.NET 4.5编译器发出)的IL:为什么编译器发出一个stloc后跟一个ldloca?
.maxstack 2
.locals init (float64 V_0,
float64 V_1)
IL_0000: ldc.r8 2.00
IL_0009: stloc.0
IL_000a: ldloca.s V_0
IL_000c: call instance string [mscorlib]System.Double::ToString()
IL_0011: call void [mscorlib]System.Console::WriteLine(string)
IL_0016: ldloc.0
IL_0017: ldc.i4.5
IL_0018: call float64 [mscorlib]System.Math::Round(float64,
int32)
IL_001d: stloc.1
IL_001e: ldloca.s V_1
IL_0020: call instance string [mscorlib]System.Double::ToString()
IL_0025: call void [mscorlib]System.Console::WriteLine(string)
IL_002a: ret
而且我注意到IL_001d的指示, IL_001e。它们对我来说似乎是多余的,将值存储在本地并在此之后加载相同的值。删除它们并重新组装IL给我一个NullReferenceException,所以我猜测它有一些指向。但我无法弄清楚。
那么NullReferenceException从哪里来?为什么编译器会发出这两条指令? 除了上面给出的IL之外,没有更多的IL,当然除了一些元。
谢谢你的回答。根据你的指针进行更多的研究之后,我现在完全可以了解它。 '调用'操作码需要将参考推送到堆栈上,并且在堆栈上推入一个双精度值不能满足该要求。所以它需要存储在一个变量中,并且该变量的引用被压入堆栈,所以'call'很快乐。而且我认为发生了NullReferenceException,因为double值表示的地址没有任何内容。 – Vincent 2014-11-02 17:32:13
我认为在这种情况下,异常类型取决于堆栈顶部的当前值:它可能是NullReferenceException中的任何内容,将垃圾打印到访问冲突。 – 2014-11-03 08:24:11
关于'System.Double :: ToString'调用,这是实例方法,它期望堆栈中'Double'结构的地址。由于'double'变量具有与'Double'结构相同的内存布局,这使得'ToString'方法很开心。顺便说一句,这段代码表明,为'int,double'和类似类型调用'ToString'不会导致装箱。 – 2014-11-03 08:27:17