.net - 这个 CIL 代码是做什么的?为什么需要第3步?

标签 .net for-loop cil

在我正在阅读的《Pro C# 2008 和 .NET Platform》一书中,有一章是关于 CIL 的,其中有一些我感到困惑的代码。

enter image description here

为什么突出显示的步骤是必要的?据我所知,这就是代码正在做的事情。

  1. 创建局部整型变量“i”并将其初始化为 0(如果未显式赋值,则整数始终初始化为 0)
  2. (IL_0000) 局部变量 [0](即“i”)的值加载到堆栈中
  3. (IL_0001) 然后将该值从堆栈中弹出并再次分配给“i”。 。 。为什么? “i”已经是 0!

最佳答案

从内存的角度来看,您可以认为没有必要将 i 初始化为 0,因为初始化的 int32 变量的默认值为 0。

但是,编译器在源代码中保留了循环的语义信息。毕竟,变量 i 在 for 语句中被赋值为 0,并且该信息最终在 IL 中序列化。无论如何,这个语句很可能会被 JIT 优化掉。至少 Mono 的 JIT 是这样做的。从 CIL 的角度来看,可以很容易地看到正在发生的事情:

.locals init (int32 i)

ldc.i4.0
stloc.0

// i = 0

br.s loop_test

loop_body:
    ldloc.0
    ldc.i4.1
    add
    stloc.0

    // i = i + 1

loop_test:
    ldloc.0
    ldc.i4.s  10
    blt.s loop_body

    // i < 10  

ret

在 CIL 级别,for 基本上是:

  • 预先测试的循环(在首次执行主体之前测试条件,因此 br,无条件分支),
  • 循环体之前的变量初始值设定项,
  • 对正文末尾的初始化变量进行操作。

很容易直观地识别上面 CIL 中元素的不同之处。

关于.net - 这个 CIL 代码是做什么的?为什么需要第3步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5840020/

相关文章:

linux - bash中的德语到英语 float 系统

delegates - 是否有可能扩展 System.Delegate?

.net - MethodImplOptions.InternalCall 的意义何在?

.net - .net 中的隐藏马尔可夫模型实现?

c# - 如果类具有 JsonExtensionData,如何使用 Json.NET 订购属性?

Javascript 二维数组获取每个元素

c# - OpCode.Call to Generic Method in different assembly 使用原始 IL

c# - .Net 接口(interface)的二进制兼容性

c# - NHibernate 查询最近的记录

javascript - 为什么这个循环每次迭代重复两次?