打算无限递归,无返回函数

时间:2021-07-08 05:38:11

Infinite recursion is most often not desired, and when it happens it usually causes a stack overflow or segfaults.

无限递归通常是不需要的,当它发生时通常会导致堆栈溢出或分段错误。

But for theory's sake, and plain curiosity, I've been thinking if it'd be possible to create actual infinite recursion, intentionally.

但出于理论的考虑,以及纯粹的好奇心,我一直在想,是否有可能会有意地创建一个实际的无限递归。

Working in C++ and C where the stack, usually, grows for each function call, and each function returns and pops the part of the stack it handled.

在c++和C语言中工作,在这些语言中,堆栈通常随着每个函数调用而增长,每个函数返回并弹出它处理的堆栈的部分。

Here's the thought. Would it be possible to force a function to clear out it's own stack space and then call another function so that the new function effectively replaces the first function, without the first function needing to return and then fire again via a loop.

这是思想。是否有可能强制一个函数清除它自己的堆栈空间,然后调用另一个函数,使新函数有效地取代第一个函数,而不需要返回第一个函数,然后通过循环再次触发。

I'm not only thinking about plain loops as a possible use for this, if there would be any. Loops usually do a good job at what they do. But what if you were to use it for sending signals through a node network, that carry on indefinitely in their own process threads until they reach a certain condition. It might be a tool that could be used for some problems.

我不仅考虑了纯循环的可能用途,如果有的话。循环通常做得很好。但是,如果您将它用于通过节点网络发送信号,这些节点网络将在它们自己的进程线程中无限期地运行,直到达到一定的条件。它可能是一个可以用来解决某些问题的工具。

Remember, I'm not really asking if it's practical, only if it's possible to do. For science!

记住,我并不是真的问它是否可行,只是问它是否可行。科学!

3 个解决方案

#1


15  

Would it be possible to force a function to clear out it's own stack space and then call another function so that the new function effectively replaces the first function

是否可能强制一个函数清除它自己的堆栈空间,然后调用另一个函数,以便新的函数有效地替换第一个函数

This is used for tail-call-optimization, so yes, it is possible and used in practice. In languages like C++ this a nice feature, because sometimes algorithms are simpler to express using recursion, but more efficiently implemented using a loop. The transformation can in some cases be done automatically by the compiler.

这用于尾部调用优化,因此,是的,这是可能的,并在实践中使用。在c++等语言中,这是一个很好的特性,因为有时使用递归表示算法更简单,但使用循环实现更有效。在某些情况下,转换可以由编译器自动完成。

#2


5  

There is a technique called trampolining that is used to implement continuation-passing style programming without the use of tail-call optimization. If you consider any language without support for TCO, such as JavaScript, and research solutions for CPS in that language, then it is likely that the solution involves trampolining.

有一种称为蹦床的技术,用于实现连续传递样式的编程,而不使用尾部调用优化。如果您考虑任何不支持TCO的语言,比如JavaScript,以及用这种语言研究CPS的解决方案,那么解决方案很可能涉及到蹦床。

Essentially, with trampolining there is a function called a trampoline which iteratively calls thunk-returning functions.

本质上,蹦床有一个叫做蹦床的函数,它迭代地调用返回thunk的函数。

I know that you said "without the first function needing to return and then fire again via a loop"—that's what trampolining is—but considering that this is C++, leaving scopes by, for example, returning is central to the core design of C++'s automatic resource management via destructors (see: RAII). You could alternatively use C's setjmp()/longjmp() functions to wipe out stack, but then you would need to be very careful in making sure that all resources are released properly.

我知道您说过“没有第一个函数需要返回,然后再通过循环触发”——这就是蹦床——但是考虑到这是c++,例如,离开作用域,返回是c++通过析构函数自动资源管理的核心设计(参见:RAII)。您也可以使用C的setjmp()/longjmp()函数清除堆栈,但是您需要非常小心地确保所有资源都被正确释放。

#3


2  

This does remind me of an optimisation that can be done in assembler code. Say you have this:

这确实让我想起了可以在汇编代码中完成的优化。你有说:

  call FuncA
  call FuncB

you can replace it with:

你可以用:

  push ReturnAddress
  push FuncB
  jmp FuncA
ReturnAddress:

This causes the ret at the end of FuncA to jump to FuncB directly rather than back to the caller and then onto FuncB. Not really possible in higher level languages.

这就导致了FuncA末端的ret直接跳转到FuncB,而不是返回到调用者,然后再跳转到FuncB。在高级语言中是不可能的。

There's also this:

还有这个:

 call FuncA
 ret

which can be changed to:

可更改为:

 jmp FuncA

#1


15  

Would it be possible to force a function to clear out it's own stack space and then call another function so that the new function effectively replaces the first function

是否可能强制一个函数清除它自己的堆栈空间,然后调用另一个函数,以便新的函数有效地替换第一个函数

This is used for tail-call-optimization, so yes, it is possible and used in practice. In languages like C++ this a nice feature, because sometimes algorithms are simpler to express using recursion, but more efficiently implemented using a loop. The transformation can in some cases be done automatically by the compiler.

这用于尾部调用优化,因此,是的,这是可能的,并在实践中使用。在c++等语言中,这是一个很好的特性,因为有时使用递归表示算法更简单,但使用循环实现更有效。在某些情况下,转换可以由编译器自动完成。

#2


5  

There is a technique called trampolining that is used to implement continuation-passing style programming without the use of tail-call optimization. If you consider any language without support for TCO, such as JavaScript, and research solutions for CPS in that language, then it is likely that the solution involves trampolining.

有一种称为蹦床的技术,用于实现连续传递样式的编程,而不使用尾部调用优化。如果您考虑任何不支持TCO的语言,比如JavaScript,以及用这种语言研究CPS的解决方案,那么解决方案很可能涉及到蹦床。

Essentially, with trampolining there is a function called a trampoline which iteratively calls thunk-returning functions.

本质上,蹦床有一个叫做蹦床的函数,它迭代地调用返回thunk的函数。

I know that you said "without the first function needing to return and then fire again via a loop"—that's what trampolining is—but considering that this is C++, leaving scopes by, for example, returning is central to the core design of C++'s automatic resource management via destructors (see: RAII). You could alternatively use C's setjmp()/longjmp() functions to wipe out stack, but then you would need to be very careful in making sure that all resources are released properly.

我知道您说过“没有第一个函数需要返回,然后再通过循环触发”——这就是蹦床——但是考虑到这是c++,例如,离开作用域,返回是c++通过析构函数自动资源管理的核心设计(参见:RAII)。您也可以使用C的setjmp()/longjmp()函数清除堆栈,但是您需要非常小心地确保所有资源都被正确释放。

#3


2  

This does remind me of an optimisation that can be done in assembler code. Say you have this:

这确实让我想起了可以在汇编代码中完成的优化。你有说:

  call FuncA
  call FuncB

you can replace it with:

你可以用:

  push ReturnAddress
  push FuncB
  jmp FuncA
ReturnAddress:

This causes the ret at the end of FuncA to jump to FuncB directly rather than back to the caller and then onto FuncB. Not really possible in higher level languages.

这就导致了FuncA末端的ret直接跳转到FuncB,而不是返回到调用者,然后再跳转到FuncB。在高级语言中是不可能的。

There's also this:

还有这个:

 call FuncA
 ret

which can be changed to:

可更改为:

 jmp FuncA