如果您在使用 MSVC 的 Windows 上,您可以使用异常(结构化异常处理,SEH)来实现类似的效果。正如 thiton 所说,在其他平台上,您可以使用 setjmp/longjmp。
使用 SEH,您可以执行以下操作(没有尝试过,因为我没有准备好 Visual Studio 的 Windows):
#include "stdio.h"
#include "Windows.h"
void func_b() {
printf("In func_b()\n");
// return safely to main
RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL);
printf("At end of func_b()\n");
}
void func_a() {
printf("In func_a()\n");
func_b();
printf("At end of func_a()\n");
}
void main() {
printf("In func_a()\n");
__try {
func_a();
}
__except (GetExceptionCode() == 1) {
printf ("Early return to main()\n");
}
printf("At end of main()\n");
}
RaiseException 调用导致控制向上堆栈,直到在 main() 中捕获异常。这不是真正的“return^2”,因为调用函数(main)必须配合。通常,您还需要与您想要跳过的函数(此处为 func_a)合作,因为它们可能会做一些事情并需要清理。只是说“从 func_b 返回,并停止 func_a 正在做的任何事情并从那里返回”可能是非常危险的。但是,如果您使用异常,您可以将代码包装在 func_a 中的 try/finally 子句中:
FILE* f;
__try {
f = fopen("file.txt", "r");
func_b();
}
__finally {
fclose(f);
printf("Cleanup for func_a()\n");
}
这在本机支持异常的语言(C++、Python、Java 等)中当然要好得多,并且不只是将其作为专有扩展加以固定。
请注意,有些人认为将异常用于控制流是不好的做法,并说应为真正的异常事件(如 IO 错误)保留异常。在许多情况下它确实有意义(例如,您正在解析某些东西,并在堆栈深处意识到您必须倒带并以不同的方式解析某些东西,您可以抛出自定义异常)。一般来说,我会说尽量不要太聪明,尽量不要做会让你的程序的读者感到困惑的事情。当您似乎需要使用这样的技巧时,通常有一种方法可以重组程序,以一种对语言来说很自然的方式来完成。或者,您使用的语言可能不是解决问题的好选择。