3

考虑以下 C# 函数:

void DoWork()
{
    ...
}

C# 文档指出:

当用作方法的返回类型时,void 指定该方法不返回值

这似乎很简单,在大多数情况下,这适合作为一个公平的定义。

但是,对于许多低级语言(即 C),“void”的含义略有不同。具体来说,所有代码块都必须返回一些东西。因此,void是空指针的表示,它是“无”的表示。在这种情况下,您不需要return在代码中包含语句,因为任何不返回值的块语句都会自动返回空指针。

这是 C# 所做的,还是在void调用函数时,它是否执行代码块并返回,甚至没有包含 void 值的指针?

4

3 回答 3

5

首先,C# 被编译成 IL,因此 JIT 后的最终表示可能会有所不同。

使用 void 方法,IL 中的方法签名将被标记为void,并且ret操作码仍然存在。这意味着,从 IL 的角度来看,调用堆栈上的“返回”值可能存在也可能不存在,但它永远不会被复制并在调用站点上使用。ret操作码只会在返回值存在的情况下推送返回值,并且返回void方法中不需要存在此值,因此在许多情况下,它不会返回任何内容,即使从低级概念的角度来看也是如此。

但是,对于许多低级语言(即 C),“void”的含义略有不同。具体来说,所有代码块都必须返回一些东西。

在 CLR 中情况并非如此。void 方法可以真正不返回任何内容,因为ret操作码允许不返回任何内容。见OpCodes.Ret

从当前方法返回,将返回值(如果存在)从被调用者的评估堆栈推送到调用者的评估堆栈。

于 2013-08-15T19:33:37.503 回答
2

如果此规范与官方语言规范类似,则未定义 void 方法/函数的返回值,这意味着,如果您想要 null 值,最好显式使用 null 而不是 this。

在 C 中,使用 void 函数的返回值来获取空值是一种不好的形式。这是因为:

  1. 会让下一个人感到困惑,
  2. 这没有道理。如果你想要 null,请使用 null。如果您希望 void 函数根据其计算返回一个值,请不要使用 void 返回类型,并且
  3. 最重要的是,由于它在技术上是不正确的,即使代码在当前版本的编译器上编译,它也可能在未来的版本中根本无法编译,或者行为可能会意外改变。

编辑:此外,如果这个词assembly没有让你的脊椎发冷......

在 C 编译成的底层 x86 汇编代码中,void 函数实际上什么都不返回。从函数返回值的想法实际上是由编译器实现的,所以如果你告诉编译器你不希望某些东西有返回值,那么就不会有返回值。

该文档ret对指令以及它如何适应子例程调用约定有很好的解释(不幸id的是,该文档中的元素很少而且相距甚远,因此需要滚动一点。但它就在那里。ret在页面上搜索)。

于 2013-08-15T19:41:47.703 回答
0

在 MSIL 中,Ret 可以选择返回一个值,因此 void 方法不返回任何内容。请参阅http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ret.aspx

我不确定当 MSIL 是 JIT 时如何处理的。

于 2013-08-15T19:30:03.923 回答