10

一个简单的问题,但我还没有在 Stack Overflow 上找到明确的答案。

    struct MyStruct { int x, y, z; }

    MyStruct GetMyStruct() => new MyStruct();

    static void Main()
    {
        var x = GetMyStruct();      // can boxing/unboxing ever occur?
    }

从函数返回时, C#结构(值类型)是否总是复制到堆栈中,无论它有多大?我不确定的原因是,对于 MSIL 以外的某些指令集(例如 x86),返回值通常需要适合处理器寄存器,并且不直接涉及堆栈。

如果是这样,是否是调用站点在CLR堆栈上为(预期的)值返回类型预分配空间?

[编辑:答复摘要:] 对于原始问题的意图,答案是否定的;CLR永远不会(默默地)将一个结构装箱,只是为了将其作为返回值发送。

4

2 回答 2

10

这是 JIT 编译器的一个重要实现细节。一般来说,如果结构足够小并且具有简单的成员,那么它会在 CPU 寄存器中返回。如果它变得太大,那么调用代码会在堆栈上保留足够的空间,并将指向该空间的指针作为额外的隐藏参数传递。

它永远不会被装箱,除非方法的返回类型当然是对象

Fwiw: this is also the reason that the debugger cannot display the return value of the function in the Autos window. Painful sometimes. But the debugger doesn't get enough metadata from the JIT compiler to know exactly where to find the value. Edit: fixed in VS2013.

于 2010-09-18T19:07:07.610 回答
6

每当您想将结构视为 时,它就会被装箱object,因此如果您调用Func并将结果分配给对象,它将被装箱。

例如这样做

 object o = Func();

将产生以下 IL

L_0000: call valuetype TestApp.foo TestApp.Program::Func()
L_0005: box TestApp.foo
L_000a: stloc.0 

这表明返回值是装箱的,因为我们将它分配给 type 的引用object

如果将它分配给类型的变量,Foo它不会被装箱,因此它会被复制并且值存储在堆栈中。

此外,装箱在这里并不能真正帮助您,因为它涉及创建一个对象来表示结构的值,并且在装箱操作期间有效地复制了这些值。

于 2010-09-18T18:31:22.003 回答