g++ コンパイラには、ゼロコストの例外処理機能があります。私の理解では、try
何もしませんが、例外がスローされると、例外ハンドラーのサブルーチンが実行されます。このような:
void foo() {
try {
bar(); // throws.
} catch (Type exc) {
baz();
}
}
疑似コード (c-stylish) では、次のようになります。
void foo() {
bar();
return;
catch1_Type:
baz();
}
bar() スロー。例外ルーチンは次のことを行います。
ああ、戻りアドレスは関数 foo() にあります! また、戻りアドレスは最初の try-catch ブロックにあり、型 Type をスローするため、例外ハンドラー ルーチンはアドレス foo+catch1_Type にあります。スタックをクリーンアップして、そこにたどり着きます!
今私の質問: C でそれを実装する方法はありますか? (gcc でサポートされている C 方言に興味がありますが、C99 以降でもかまいません)。catch1_Type
ラベルのアドレスを取得する方法はわかりませんが、スタックの検査とトラバーサルに libunwind などを使用できることは知っています。できない場合があります。
例外ハンドラーは別の関数である可能性がありますが、それは同様に問題ありませんが、その他の関数でスタックフレームのローカル変数のアドレスを取得する方法はfoo
? それも無理のようです。
では・・・何かいい方法はないでしょうか?これでアセンブラに入りたくないのですが、他のすべてが失敗した場合も受け入れられます(ローカル変数ですが、さまざまな最適化レベルを使用している場合、それらがどこにあるのかわかりません)。
明確にするために、この質問の目的はsetjmp/longjmp アプローチを避けることです。
編集:私は非常にクールなアイデアを見つけましたが、完全には機能しません:
gcc のネストされた関数。彼らは何ができますか?
- ローカル変数にアクセスでき、
- 親関数でローカル ラベルに移動する可能性があります。
- ネストされた関数にポインターを渡す場合、関数の呼び出し先から呼び出すことができるため、呼び出し先のポインターで使用できます。
私がゼロコストで何かをするのを妨げる欠点:
- 未使用の場合、-O0 レベルでも最適化されます。これについて何かできることはありますか?できれば、例外がスローされたときにシンボル名でアドレスを取得でき、スローされない場合はコストがかからない例外を実装するだけです...