具有全局定义变量的递归比没有全局定义变量的递归函数获得更多堆栈。为什么?(跳入C++)

Iva*_*vic 0 c++ recursion function

我正在学习 C++ 以及来自 Alex Allain 的“Jumping into C++”的其他书籍,并且正在学习递归。有一个程序示例可以计算出我的计算机可以处理多少递归,直到出现“堆栈溢出错误”或在我的情况下出现“分段错误”。

在使用给定的示例代码之前,我编写了一个简短的程序来测试它,它表明我的代码可以处理比给定的示例代码多一倍的递归。我的问题:为什么会这样,因为它几乎是相同的模式 - 一个函数调用自身并迭代一个整数。

  1. 为什么在出现错误之前要进行两倍以上的递归?在我的理解中,两种算法都使用了相同数量的堆栈,并且在我的理解中它们应该或多或少地使用相同的数量。

第二,为什么会出现分段错误而不是堆栈溢出?

我真的很想了解 C++ 编程,并希望能够编写使用少量系统资源的“廉价”程序,这确实是必要的。

我的代码:

#include <iostream>
using namespace std;


int i = 1;

void recurse ()
{

    i = i + 1;
    cout << "number: " << i << endl;

    recurse();
}

int main()
{
    recurse();
}

Run Code Online (Sandbox Code Playgroud)

本书中的代码示例:

#include <iostream>

using namespace std;


void recurse(int count)
{
    cout << count << endl;
    recurse(count + 1);
}

int main()
{
    recurse(1);
}
Run Code Online (Sandbox Code Playgroud)

我的输出: 我系统上两个示例的输出屏幕截图,以查看我所指的差异

使用编译器 Linux g++ -std=c++17 (Arch Linux)

Max*_*hof 5

两个版本的代码都有未定义的行为。编译器可以很容易地证明该recurse函数会无限递归,并且最终也会出现整数溢出。

C++ 标准明确表示对具有未定义行为的程序的行为没有限制。您可能会遇到堆栈溢出、分段违规、您的硬盘驱动器可能被格式化、可能发射核导弹、恶魔可能从您的鼻子里飞出、程序可能什么都不做,或者(最糟糕的是)它可能不小心做了什么你自找的。

因此,使用具有未定义行为的 C++ 程序来测试系统的限制或多或少毫无意义。

如果您删除输出,请参阅此处了解两个编译器如何在优化下转换您的代码:https :
//godbolt.org/z/Lqln9n

请注意如何clang查看未定义的行为并将其替换为“什么都不做并返回”。你不会在那个编译器上崩溃,程序什么都不做!而 MSVC 将无限递归优化为一个简单的无限循环 ( loop: jmp loop)。它会永远重复这条指令,而不是得到警告中提到的堆栈溢出。

混合输出后,编译器可能会再次做不同的事情。但在每种情况下,除了“编译器决定这样做”之外,运行程序并没有得到任何有意义的答案。您可以检查生成的汇编代码(见上文)以查看编译器做了什么,然后使用它来解释您看到的行为。但我必须重申,给定的 C++ 代码没有定义的行为,可能会做任何事情