CIL中的nop有什么意义

Dim*_*tri 13 c# cil

所以我在C#中编写了以下代码.

class Test
{
    int a;
    System.IO.StreamReader reader;

    public Test()
    {
        a = 5;
        reader = new System.IO.StreamReader(String.Empty);
    }
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

有3个nop命令.(据我所知,这表示无操作).这些命令的需要是什么.我的意思是,如果根本没有命令,那会有什么不同nop

Han*_*ant 19

它们在为程序写入.pdb文件时由C#编译器使用.其中包含调试信息,其中包含代码的文件+行号信息.调试器使用它来查找需要注入INT 3指令的机器代码,以便在设置断点时让程序停止执行.抖动为MSIL中的每个Opcodes.Nop发出NOP机器代码指令.

在设置断点时使用第一个nop public Test().请注意,它是基础构造函数调用之后注入的,以便变量在Auto/Locals/Watch调试窗口中变为有效.

在第一个{花括号上设置断点时使用第二个nop.该行根本不生成任何代码,因此非常需要伪造的MSIL指令.

第三个nop的相同故事,为最后一个大括号生成.当您在该断点上设置断点时,您可以检查方法返回值(如果有).在Debug + Windows + Registers窗口中间接可见.在VS2013中得到改进.

因此,这只是帮助调试程序,它们使断点可以预测.在构建程序的Release配置时,不会生成这些NOP .C#项目具有Debug和Release配置的一个重要原因.你仍然可以调试一个Release版本,但这是一个相当混乱的体验,让你怀疑你的理智:)