所以我正在玩一些思想实验,我想象当两个函数相互递归时会发生什么。其中一个就是如果两个函数都可能陷入无限循环的话。
为此,我想到了这个简单的例子:
#include <iostream>
#include <cstdlib>
int foo(int x);
int bar(int x);
int foo(int x)
{
return bar(x + 1);
}
int bar(int x)
{
return foo(x - 1);
}
int main(int argc, char **argv)
{
if (argc > 1)
std::cout << "The value is: " << foo(atoi(argv[1])) << std::endl;
return 0;
}
有趣的是,如果用g ++编译它,这实际上绝对没有打印出来。用任何-O开关编译它就会陷入无限循环。
思考?这可能是一个编译器错误,还是这是预期的?我认为在-O优化的情况下,它会意识到foo(x)和bar(x)只返回x。
我没想到它实际上“优化掉了”这个电话并完全忽略了打印出“标准输入的价值”。
编辑:我使用GCC 4.5.0在Cygwin下将其编译为g ++ source.cpp(-O1 / 2/3)。 -OX版本实际上无限循环而没有堆栈溢出。
答案 0 :(得分:2)
由于你没有指定你所使用的C ++,我将给出C ++ 0x答案:
This is实际上是undefined behaviour in C++0x。
如果您使用的是C ++ 03,我无法完全解释这种行为,但由于您的堆栈最终会溢出,因此您仍然处于依赖于实现的行为范围内。期待任何理智发生在这里是一个愚蠢的差事。
答案 1 :(得分:1)
从数学的角度来看, f(x)= b(x + 1)和 b(x)= f(x - 1) 不足以定义 f 和 b 。一种可能的解决方案是 f(x)= x 和 b(x)= x - 1 ,而另一个是 f(x)= 0 和 g(x)= 0 (还有更多的方法)。从数学上讲,函数应返回的问题没有答案。从计算的角度来看,情况更糟,因为毕竟,您没有定义数学函数,而是指定如何执行计算。 foo(x - 1)
表示“当我们将foo()
的值作为参数传递时,执行函数x - 1
中指定的计算”,类似于bar(x + 1)
。因此,当每个函数无条件地说,要调用另一个函数时,您已指定希望进行无限递归。正如其他人所提到的,某些语言(或语言版本)将此视为明确定义的情况(期望的结果是程序挂起),而其他语言将其视为未定义的情况(即编译器可能会做任何喜欢的事情) )。
答案 2 :(得分:0)
由于你的递归没有停止条件,你进入无限循环是很自然的。你的假设,这些函数返回“只是x”是错误的。他们一定会永远不会回来。
编译器不能只是优化掉递归。