Functional programming 跳转和呼叫的区别
跳转指令和呼叫指令有何不同?它与更高级别的概念(如GOTO或过程调用)有何关系?(我的比较正确吗?) 我是这样想的: 跳转或转到是将控件转移到另一个位置,并且控件不会自动返回到调用它的点 另一方面,调用或过程/函数调用返回到调用它的点。由于本质上的这种差异,语言通常使用堆栈,并推送堆栈框架“记住”每个调用的过程返回的位置。这种行为也适用于递归过程。在尾部递归的情况下,不需要为每个调用“推送”堆栈帧Functional programming 跳转和呼叫的区别,functional-programming,recursion,computer-science,Functional Programming,Recursion,Computer Science,跳转指令和呼叫指令有何不同?它与更高级别的概念(如GOTO或过程调用)有何关系?(我的比较正确吗?) 我是这样想的: 跳转或转到是将控件转移到另一个位置,并且控件不会自动返回到调用它的点 另一方面,调用或过程/函数调用返回到调用它的点。由于本质上的这种差异,语言通常使用堆栈,并推送堆栈框架“记住”每个调用的过程返回的位置。这种行为也适用于递归过程。在尾部递归的情况下,不需要为每个调用“推送”堆栈帧 您的回答和评论将不胜感激。如果您正在讨论x86汇编中的CALL/JMP或类似的东西,您基本上是对的
您的回答和评论将不胜感激。如果您正在讨论x86汇编中的CALL/JMP或类似的东西,您基本上是对的。主要区别在于:
- JMP执行到某个位置的跳转,而不做任何其他操作
- 调用将当前指令指针推送到堆栈上(而不是在当前指令之后),然后将JMPs推送到该位置。通过RET,你可以回到原来的位置
movl $afterJmp, -(%esp)
jmp location
afterJmp:
而不是打电话。我想你已经大致了解了 这取决于体系结构,但通常在硬件级别:
- 一条跳转指令将改变程序,以在程序的不同部分继续执行
- call指令将当前程序位置(或当前位置+1)推送到,并跳转到程序的另一部分。然后,返回指令将从调用堆栈中弹出该位置,并跳回原始位置(或原始位置+1)
GOTO
,而调用指令接近于过程/函数调用
此外,由于在进行函数调用时使用调用堆栈,通过递归将过多的返回地址推送到调用堆栈将导致错误
在学习汇编时,我发现处理处理器比处理x86处理器更容易,因为它的指令更少,操作更简单。关于跳转和调用之间的区别,你说得完全正确 在带有尾部递归的单个函数的示例中,编译器可能能够重用现有堆栈框架。但是,使用相互递归的函数可能会变得更复杂:
void ping() { printf("ping\n"); pong(); }
void pong() { printf("pong\n"); ping(); }
考虑以下情况:ping()和pong()是更复杂的函数,具有不同数量的参数。详细讨论了GCC的尾部递归实现。根据微处理器,首先检查条件,然后执行跳转操作(转到其他代码),并且不返回。
调用操作就像是在
c
语言中调用函数,当函数被执行时,它会返回来完成它的执行。对您的想法有一个更正:我们不需要堆栈框架,因此可以简单地在那里使用JMP,这不仅是尾部递归,而且通常是尾部调用(只要参数设置正确)。当您说:“调用只是使用JMP实现的一个方便函数。”这是否意味着调用不是原子的(一条处理器指令)?你的意思是,就像一个线程可以在movl之间中断一样,但在jmp本身之前,如果一个调用将作为两条指令来实现?查看文档:,它说该过程确实首先移动堆栈上的地址,然后跳转,清楚地将其表示为一个序列。我不明白为什么它应该是原子的,另外,这又有什么关系?这很简单这与jmp之后您会被中断的情况相同,因为jmp是无条件的。如果CALL
记住了您跳转的位置,这意味着太多CALL
s可能会溢出堆栈(如果您不RET
urn),而使用JMP
则不可能损坏堆栈,但另一方面,除非存储位置,否则无法跳回从您自己跳转的位置。是否正确?在本例中,C的goto
应等于JMP
。由于CALL
不执行任何条件检查,因此用于比较的唯一有效跳转指令是JMP
,它无条件跳转。