所以我用C#写了下面的代码。
class Test
{
int a;
System.IO.StreamReader reader;
public Test()
{
a = 5;
reader = new System.IO.StreamReader(String.Empty);
}
}
IL 中类的构造函数如下所示
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 33 (0x21)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldc.i4.5
IL_000a: stfld int32 Test2.Test::a
IL_000f: ldarg.0
IL_0010: ldsfld string [mscorlib]System.String::Empty
IL_0015: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string)
IL_001a: stfld class [mscorlib]System.IO.StreamReader Test2.Test::reader
IL_001f: nop
IL_0020: ret
} // end of method Test::.ctor
有 3 个 nop
命令。 (据我所知,这代表没有操作)。这些命令需要什么。我的意思是如果根本没有命令而不是 nop
最佳答案
C# 编译器在为您的程序编写 .pdb 文件时使用它们。其中包含调试信息,其中包括代码的文件+行号信息。调试器使用它来查找需要注入(inject) INT 3
指令以使程序在您设置断点时停止执行的机器代码。抖动为 MSIL 中的每个 Opcodes.Nop 发出一条 NOP 机器码指令。
当您在 public Test()
上设置断点时,将使用第一个 nop。请注意,它是在基础构造函数调用之后注入(inject)的,因此this变量在自动/本地/监视调试窗口中变得有效。
当您在第一个 { 花括号上设置断点时,将使用第二个 nop。该行根本不生成任何代码,因此非常需要伪造的 MSIL 指令。
第三个 nop 的故事相同,为最后一个 } 大括号生成。当您在该断点上设置断点时,您可以检查方法返回值(如果有)。在 Debug + Windows + Registers 窗口中间接可见。在 VS2013 中得到改进。
所以这只是帮助调试您的程序,它们使断点的行为可预测。当您构建程序的发布配置时,这些 NOP 不会生成。 C# 项目具有调试和发布配置的一个重要原因。您仍然可以调试 Release 版本,但是这是一种令人困惑的体验,让您怀疑自己的理智 :)
关于c# - CIL中的nop有什么意义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19206428/