C# 如何返回结构体

mFe*_*ein 6 c# clr struct class return-value

结构是值类型,因此每次对结构进行操作时都会完全复制。由于它们是值类型,因此结构在堆栈中分配,而不是在堆中分配。

我可以看到当结构作为参数传递时,结构如何降低方法的性能,因为它们总是在堆栈中复制,特别是如果它们很大并且有很多内部字段。

但我很好奇 C# 如何处理结构的返回。

在 C 中,返回是通过寄存器进行的,或者如果要返回的值对于寄存器而言太大,则通过使用堆的引用进行返回。几乎所有 C# 结构教程都说结构存在于堆栈中,而不是存在于堆中。

所以在下面的代码中:

MyStruct ms = GetMyValue();
Run Code Online (Sandbox Code Playgroud)

哪里GetMyValue()

MyStruct GetMyValue();
Run Code Online (Sandbox Code Playgroud)

C# 将如何处理 ms 变量的结构返回?特别是如果它对于寄存器来说太大了?它实际上会将其复制到堆中,然后再次将其复制回方法的调用者并将其分配给 ms 吗?


编辑:

针对帖子中留下的评论:

  1. 在发布这篇文章之前,我已经阅读了一些关于 C# 结构的教程,特别是本教程stack使用这个词的次数多得我都懒得数了。这个MSDN 教程也谈到了堆栈,虽然它是 2003 年的,但我认为从那时起结构就没有改变。

  2. 我知道这可能与 C# 根本无关,但实际上是 JIT 编译器本身或 CLR 或其他我不知道的东西的问题。这就是我提出问题的目的,即了解更多有关 C# 内部工作原理的信息,即使这实际上与语言本身无关。

  3. 有C函数调用约定,对我的帖子最好的支持是这篇StackOverflow帖子。当我第一次在这里发布它时,我只是说出了我记得的内容,但由于 SO 答案说:

    至于你的具体问题,这取决于ABI。有时如果返回值大于4字节但不大于8字节,可以分为EAX和EDX。但大多数时候,调用函数只会分配一些内存(通常在堆栈上)并将指向该区域的指针传递给被调用函数。

    我在这一点上可能是错的,我说可能是,因为答案说通常

  4. 我想了解如何处理结构的真正原因是因为我有一个项目,我必须多次读取串行端口以轮询数据,该数据将由方法返回。

    由于数据只是一些字节,我认为我可以从结构中获得一些性能,而不是使用类来抽象串行端口传入的字节,但如果将作为堆分配return传递,我对性能提高的期望可能是错误的struct

    是的,我知道,我可以进行简单的测试并比较性能,但我想真正了解它在幕后是如何完成的,而不仅仅是记住模拟的结果。我喜欢知道我所使用的东西实际上是如何工作的,而不仅仅是学习如何使用它们。

usr*_*usr 2

值类型不仅仅位于堆栈上。它们也生活在田野和阵列中。与引用类型的主要区别在于值类型是按值复制的并且没有标识。堆栈与堆的想法是错误的。

在 C 中,返回是通过寄存器进行的,或者如果要返回的值对于寄存器而言太大,则通过使用堆的引用进行返回

不涉及堆。调用者为要放置的返回值分配空间。它传递一个指向该空间的指针。被调用者可以填充该空间。.NET CLR 也执行此操作。当然,这是一个实现细节。

但我想真正学习

这是非常好的。你无法测试我刚才告诉你的内容。你需要对别人所说的话更加挑剔。要么你的教程很糟糕,要么你阅读的方式不准确。

我可以看到当结构作为参数传递时结构如何降低方法的性能,因为它们总是在堆栈中复制

我认为情况并非总是如此。我不太确定,但我认为 JIT 有时可以在寄存器中传递结构。.NET JIT 确实没有进行太多优化,但我认为这是一种在一定程度上有效的优化。可能是由某些单字段结构的存在驱动的,例如DateTime.