为什么为指针和 ref 生成的 IL 代码相同但签名不同?
Why the generated IL code for a pointer and ref is same but signatures are different?
我正在尝试找出如何在 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 Preview
,Debug Mode
。
这两种方法的实现具有相同 IL 的原因是 stind.i4
opcode:
stores an int32 value at the supplied address (type native int, *, or &).
这意味着 OpCode 适用于指针和引用,因为它们实际上都只是存储位置的地址。由于正在完成的工作除了传入的类型外是相同的,但应用相同的 OpCode,所以方法主体最终是相同的。
但这并不意味着它们是可以互换的方法。它们需要以不同的方式调用,这就是签名不同的原因。此外,这只是中间语言 - 它们可能会被 JIT 编译成不同的机器码。
请记住,IL 不是编译的最终结果,它是一种可移植到最终编译阶段的中间格式。
IL 指令根据操作数堆栈顶部项目的类型更改行为。 JIT 编译器执行类型分析并确定 stind
是处理指针还是引用,就像它确定 add
是处理整数、浮点数还是指针一样。
我正在尝试找出如何在 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 Preview
,Debug Mode
。
这两种方法的实现具有相同 IL 的原因是 stind.i4
opcode:
stores an int32 value at the supplied address (type native int, *, or &).
这意味着 OpCode 适用于指针和引用,因为它们实际上都只是存储位置的地址。由于正在完成的工作除了传入的类型外是相同的,但应用相同的 OpCode,所以方法主体最终是相同的。
但这并不意味着它们是可以互换的方法。它们需要以不同的方式调用,这就是签名不同的原因。此外,这只是中间语言 - 它们可能会被 JIT 编译成不同的机器码。
请记住,IL 不是编译的最终结果,它是一种可移植到最终编译阶段的中间格式。
IL 指令根据操作数堆栈顶部项目的类型更改行为。 JIT 编译器执行类型分析并确定 stind
是处理指针还是引用,就像它确定 add
是处理整数、浮点数还是指针一样。