JUMP和CALL之间的区别

时间:2009-02-07 09:52:19

标签: functional-programming recursion computer-science

JUMP和CALL指令有何不同?它与GOTO或程序调用等更高级别的概念有什么关系? (我在比较中是否正确?)

这就是我的想法:

JUMP或GOTO是将控件转移到另一个位置,控件不会自动返回到调用它的位置。

另一方面,CALL或过程/函数调用返回到调用它的位置。由于它们的性质不同,语言通常使用堆栈,并且推送堆栈帧以“记住”为每个被调用的过程返回的位置。此行为也适用于递归过程。在尾递归的情况下,无需为每个调用“推送”堆栈帧。

非常感谢您的回答和评论。

5 个答案:

答案 0 :(得分:23)

如果您正在讨论x86程序集中的CALL / JMP或类似内容,那么您大多数情况下都是正确的。主要区别在于:

  • JMP执行跳转到某个位置,而不执行任何其他操作
  • CALL将当前指令指针推送到堆栈上(而不是:当前指令之后的指针),然后将JMP推送到该位置。使用RET,您可以回到原来的位置。

通常,CALL只是使用JMP实现的便利功能。你可以做点什么

          movl $afterJmp, -(%esp)
          jmp location
afterJmp:

而不是CALL。

答案 1 :(得分:1)

你对跳跃和通话之间的区别是完全正确的。

在具有尾递归的单个函数的示例情况下,编译器可能能够重用现有的堆栈帧。但是,相互递归函数会变得更加复杂:

void ping() { printf("ping\n"); pong(); }
void pong() { printf("pong\n"); ping(); }

考虑ping()和pong()是使用不同数量参数的更复杂函数的情况。 Mark Probst's paper详细讨论了GCC的尾递归实现。

答案 2 :(得分:0)

我认为你有一般的想法。

这取决于架构,但一般来说,取决于硬件级别:

  • 跳转指令会更改program counter以继续执行程序的其他部分。

  • 调用指令会将当前程序位置(或当前位置+ 1)推送到call stack并跳转到程序的另一部分。然后,返回指令将弹出调用堆栈的位置并跳回原始位置(或原始位置+ 1)。

因此,跳转指令接近GOTO,而调用指令接近程序/函数调用。

此外,由于在进行函数调用时使用了调用堆栈,因此通过递归将过多的返回地址推送到调用堆栈将导致stack overflow

在学习汇编时,我发现处理RISC处理器比处理x86处理器更容易,因为它往往具有更少的指令和更简单的操作。

答案 3 :(得分:0)

对您的想法进行了一次更正:它不仅包含tail 递归,而且通常使用tail 调用,我们不需要堆栈框架,因此只需要那里的JMP(如果参数已经正确设置)。

答案 4 :(得分:-2)

根据微处理器,首先检查条件,然后执行跳转操作(转到其他代码)并且不返回。 调用操作类似于c语言中的函数调用,当执行该函数时,它返回以完成其执行。