那么子程序 呢? 栈怎么办?
如果你考虑栈的话,goto
在函数之间是没有意义的。当你跳转时,栈上会有什么内容?源函数和目标函数可能具有不同的参数和返回值。新函数将返回给谁?它的返回值是否对调用者有意义?调用者调用的是源函数,而不是目标函数。
返回给调用者?
仔细考虑一下你的例子:
int main()
{
test();
main_next:
printf("hello, world");
}
void test()
{
goto main_next;
}
当
goto
被执行时会发生什么?我认为你希望它跳回到调用
main()
函数的位置,也就是
向上跳出堆栈。这样,
goto
实际上就相当于一个
return
,可以改变调用堆栈的状态,变为:
What happens when the goto
executes? I presume you'd want this to jump up the stack back to the calling main()
function. The goto
would effectively be the same as a return
, changing the call stack from:
main() main()
| to
+--> test()
但是如果您想要跳转到不在调用栈中的函数呢?那么怎么办呢?
或者替换当前函数?
另一种解释是,goto
将用main()
代替现有的test()
调用。调用栈将从以下内容更改:
main() main()
| to |
+--> test() +--> main()
现在,main()
在递归调用自身,而更低级别的 main()
将返回到更高级别的 main()
——顺便说一下,更高级别的函数期望得到一个 void 返回值,但实际上会收到一个 int 返回值。
setjmp 和 longjmp
你可以通过使用setjmp
/ longjmp
来实现类似效果。这些函数可以保存和恢复非本地跳转的堆栈上下文,允许你在函数调用之间进行跳转。
setjmp
和 longjmp
通过 (a) 在跳转时保存和恢复完整的堆栈上下文,以及 (b) 如果堆栈上下文无效,则不允许跳转,解决了我所描述的问题。 我从手册页中引用(重点是我的):
setjmp() 和 longjmp(3) 可以用于处理程序的低级子例程中遇到的错误和中断。setjmp() 会将堆栈上下文/环境保存在 env 中,以供 longjmp(3) 稍后使用。 如果调用 setjmp() 的函数返回,则堆栈上下文将无效。
换句话说,longjmp
基本上是 C 中抛出异常的等价物。低级别的函数可以解开调用堆栈并在更高级别函数中继续执行。
它也很棘手,很少是个好主意。再次引用手册页:
setjmp() 和 sigsetjmp() 使程序难以理解和维护。如果可能,应该使用其他方法。
setjmp/longjmp
实现。具体请参考http://en.wikipedia.org/wiki/Setjmp.h - Kyle Lutz