递归 C void 函数和 return 关键字

Posted

技术标签:

【中文标题】递归 C void 函数和 return 关键字【英文标题】:Recursive C void function and return keyword 【发布时间】:2014-04-18 00:51:08 【问题描述】:

有人知道以下之间的内部差异吗:

void RecFoo1(int bar)
  if (bar == 0)
    return ;
  RecFoo1(bar - 1);

void RecFoo2(int bar)
  if (bar == 0)
    return ;
  return RecFoo2(bar - 1);

我相信,最好使用 return 关键字。如果递归函数不是 void 函数,则会收到来自-Wreturn-type 的警告。但是这两段代码是否以相同的方式编译/执行?机器的内部差异是什么?

我的函数示例很愚蠢,但它构成了一种最小示例......

【问题讨论】:

一个是合法的C,另一个不是。您不能返回 void 表达式。 【参考方案1】:

C 标准对此非常清楚,您的 RecFoo2 示例不是有效的 C 程序:

6.3.2.2 无效

空表达式的(不存在的)值(具有 type void) 不得以任何方式使用,...

6.8.6.4 返回语句

约束

带有表达式的返回语句不应出现在函数中 其返回类型为 void。

【讨论】:

谢谢,ISO C 说的很清楚:不要那样做......无论如何我想知道如何处理这样的代码...... @user3005788 它在我见过的所有编译器上都按照描述的方式工作(即没有区别)。但是,标准不鼓励这样做。【参考方案2】:

void 函数中,return 只是一个控制流操作——退出当前函数。您可以在函数的最后一行添加一个:

void RecFoo1(int bar)
  if (bar == 0)
    return ;
  RecFoo(bar - 1);
  return; // Unecessary!

但它会是多余的。

您的第二个查询无法编译 - 您无法在 void 函数中返回值。

【讨论】:

既然被调用的函数是返回类型void,那么他实际上是在返回一个吗? (只是把你的腿拉到那里。;-)) 实际上,RecFoo2 在没有警告的情况下编译 -Wall -ansi-pedantic 说:警告:ISO C 禁止在函数返回 void [-Wpedantic] 时使用表达式“返回”【参考方案3】:

没有真正的区别。其实我以为不会有什么不同,但是看看这个。

比较生成的没有优化的汇编代码(通过将-save-temps 选项传递给gcc):

diff --git a/without-expr.s b/with-expr.s
index a7577f5..e346d6f 100644
--- a/without-expr.s
+++ b/with-expr.s
@@ -18,6 +18,7 @@ L2:
        decl    %eax
        movl    %eax, (%esp)
        call    _RecFoo2
+       nop
        jmp     L1
 L4:
        nop

优化后生成的代码完全一样(我试过-O2)。

因此,如果没有优化,编译器会为 return 生成一个额外的 nop 并带有一个表达式,但这不是你应该真正关心的事情。

【讨论】:

以上是关于递归 C void 函数和 return 关键字的主要内容,如果未能解决你的问题,请参考以下文章

讲一下c语言中递归函数的使用方法有哪些?

void函数中不写return语句会占用栈内存吗?

C语言编程:用函数递归法求Fibonacci数列的前n项·

c需要注意的细节

我想用递归写斐波那契数列,c语言

c_cpp 使用void函数在C中进行递归