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」ではありません。呼び出し元の関数 (メイン) が対応する必要があるからです。一般に、ジャンプしたい関数 (ここでは 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 エラーなど) のために予約する必要があると考えています。それが理にかなっているケースがたくさんあります (たとえば、何かを解析していて、スタックの奥深くで巻き戻し、別の方法で解析する必要があることに気付いた場合、カスタム例外をスローできます)。一般に、賢くなりすぎないようにし、プログラムの読者を混乱させるようなことはしないようにしてください。このようなトリックを使用する必要があると思われる場合、言語にとって自然な方法でプログラムを再構築する方法がよくあります。または、使用している言語が問題に適していない可能性があります。