【发布时间】:2017-06-24 06:50:10
【问题描述】:
我正在尝试通过编写小型 sn-ps 代码和检查已编译的程序集来学习 CIL。所以我写了这个简单的 if 语句:
public static void Main (string[] args)
{
Int32 i = Int32.Parse (Console.ReadLine());
if (i > 0)
Console.WriteLine ("i is greater than 0");
}
而C#编译器将其编译成如下IL代码:
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 num,
[1] bool flag)
L_0000: nop
L_0001: call string [mscorlib]System.Console::ReadLine()
L_0006: call int32 [mscorlib]System.Int32::Parse(string)
L_000b: stloc.0
L_000c: ldloc.0
L_000d: ldc.i4.0
L_000e: cgt
L_0010: ldc.i4.0
L_0011: ceq
L_0013: stloc.1
L_0014: ldloc.1
L_0015: brtrue.s L_0022
L_0017: ldstr "i is greater than 0"
L_001c: call void [mscorlib]System.Console::WriteLine(string)
L_0021: nop
L_0022: ret
}
据我所知,stloc 将评估堆栈中的最高值放入局部变量中,如果我做对了,该值不会从堆栈中弹出,那么为什么编译器会将 @987654325 @ 指令紧随其后?
【问题讨论】:
-
不,stloc 确实弹出堆栈。也许 ldloc 看起来效率很低,但是 .NET 编译器的输出没有优化。重要的是它以这种方式工作,否则您将很难调试代码。它稍后会由发布版本中的 JIT 编译器进行优化。机器代码优化,而不是 CIL 优化。你不会看到等价的stloc/ldloc回来,这个变量会被存储在一个CPU寄存器中。
-
@HansPassant,但 .net 编译器会进行优化(默认情况下)-尝试编译
string s="abc";Console.WriteLine(s);之类的东西并检查输出的 IL。 -
@IDavid - 即使没有打开优化标志,C# 编译器也会执行一些优化,例如常量折叠。但是,在您关闭优化的示例中,我确实得到了 stloc.0 ldloc.0 序列,用于 LINQPad 中的“abc”文字。请参阅此处了解优化设置的作用:blogs.msdn.microsoft.com/ericlippert/2009/06/11/…