为什么在没有显式return语句的情况下,递归的返回调用会突破堆栈?

mmd*_*ger 18 c++ recursion

我看到了一个示例程序,用于演示递归,看起来它应该不起作用,但确实如此.逻辑很清楚,但为什么即使没有返回递归的函数调用它也能工作?return即使没有请求,看起来命令也会突破堆栈.这是语言标准还是gcc的东西?我在Windows和Linux上使用gcc编译的C和C++看到了它.

#include <iostream>
#include <cstdlib>

using namespace std;

int isprime(int num, int i)
{
   if (i == 1) {
      return 1;
   }
   else {
      if (num % i == 0)
         return 0;
      else
         isprime(num, i-1); // should be returned
   }
}


int main(int argc, char** argv)
{
   int input = atoi(argv[1]);
   cout << input << "\t" << isprime(input, input/2) << "\n";
}
Run Code Online (Sandbox Code Playgroud)

Jen*_*edt 20

这样的事情只有在意外地返回值恰好在调用者期望的寄存器中才有效.这仅在编译器将其作为递归函数实现时才有效.从技术上讲,使用不提供函数的函数的返回值是未定义的行为.

编辑:在现代体系结构中,函数的返回值可以在特定的硬件寄存器中传递.当您以递归方式调用函数时,在所有情况下,硬件寄存器都设置为期望值.如果偶然从递归中弹出硬件寄存器永远不会改变,那么最终会得到正确的值.

如果返回值将被放置在(递归)调用者的堆栈的某个位置,则所有这种模式都不起作用.

在任何情况下,所有这些都应该被任何现代编译器捕获并给你一个警告.如果没有,你没有一个好的编译器,或者你使用的是防御性的命令行选项.

新年前夕特别:在现实世界中,像这样的代码(带有return)甚至不会被实现为递归函数.通过不太费力的努力,您将找到该函数的迭代变体,如果您要求最大化优化,任何现代体面的编译器都应该能够找到它.


ste*_*ves 5

这里有很多取决于你的意思"它有效"吗?

为了尝试回答问题的要点,函数将在函数结束时返回,无论是否满足return语句.

我希望看到编译器警告告诉你可能的控件路径可能无法返回值,无论如何在C++中.导致未定义的行为,请参阅此问题: 不从非void返回函数返回值

我会说这个例子"工作",因为在找到一个素数并且isPrime已经返回之后,然后堆栈的下一个函数也可以自由返回.没有任何东西依赖于isPrime的返回值,所以程序将运行堆栈并输出一些东西.

...但由于行为未定义,实际获得输出的值可能是垃圾.如果你看到0和1与素数一致作为输入,那么哇.

如果您认为这是有效的,我会考虑更广泛地使用不同的值进行测试.

您是否还在使用任何"调试"设置进行构建?若是这样再次尝试关闭调试设置,因为有时会做额外的工作来保持未初始化的内存清洁.