为什么生成的指针和ref的IL代码相同但签名不同?

时间:2015-01-20 18:43:18

标签: c# pointers il ref

我正在尝试弄清楚如何在C#中重现ref修饰符的行为。

我有两种方法:

static void Foo(ref int x)
{
     x = 25;
}

unsafe static void Foo(int* x)
{
    *x = 25;
}

即使生成的这两种方法的IL代码相同,签名也不同:

Foo(ref int)的代码:

.method private hidebysig static void  Foo(int32& x) cil managed
{
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.s   25
  IL_0004:  stind.i4
  IL_0005:  ret
} // end of method Program::Foo

Foo(int*)

的代码
.method private hidebysig static void  Foo(int32* x) cil managed
{
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.s   25
  IL_0004:  stind.i4
  IL_0005:  ret
} // end of method Program::Foo

所以我的问题是,为什么签名是不同的,而生成的代码是相同的?使用指针不能执行相同的工作吗?

注意:我编译了此代码Visual Studio 2015 PreviewDebug Mode

2 个答案:

答案 0 :(得分:4)

这两种方法实现IL的原因是stind.i4 opcode

  

在提供的地址存储int32值(类型为native int,*或&)。

这意味着OpCode适用于指针和引用,因为它们实际上只是存储位置的地址。由于正在完成的工作与传入的类型不同,但应用相同的OpCode,因此方法体最终是相同的。

但这并不意味着它们是可互换的方法。他们需要以不同的方式打电话,这就是签名不同的原因。此外,这只是中间语言 - 它们很可能被JIT编译为机器代码。

答案 1 :(得分:1)

请记住,IL不是编译的最终结果,它是一种可移植的中间格式,可以提供给最终的编译器阶段。

IL指令根据操作数堆栈顶部的项目类型更改行为。 JIT编译器执行类型分析并确定stind是否正在使用指针或引用,就像它确定add是在处理整数还是浮点或指针一样。