g ++コンパイラにはゼロコスト例外処理機能があります。私の理解では、try
は何もしませんが、例外がスローされると、例外ハンドラのサブルーチンが実行されます。このように:擬似コードでCでゼロコスト例外処理を書くことはできますか?
void foo() {
try {
bar(); // throws.
} catch (Type exc) {
baz();
}
}
(C-スタイリッシュな)は次のようになります。
void foo() {
bar();
return;
catch1_Type:
baz();
}
バー()がスローされます。例外ルーチンは次の処理を行います。
ああ、戻りアドレスは関数foo()です。戻りアドレスは最初のtry-catchブロックにあり、Type型を投げるので、例外ハンドラルーチンはアドレスfoo + catch1_Typeにあります。だから、スタックをクリーンアップして、そこで終わります!
今私の質問:Cでそれを実装する方法はありますか? (gccでサポートされているCの方言に興味がありますが、C99以降も可能です)。 catch1_Type
というラベルをどのように取得するのか分かりませんが、私はlibunwindをスタック検査とトラバーサルに使用できることを知っています。それは不可能かもしれません。
例外ハンドラは、別の関数でもかまいませんが、それと同等ですが、スタックフレームのローカル変数のアドレスを取得する方法は他の関数でfoo
ですか?それはまた不可能と思われる。
だから、それを行う方法はありますか?私はこれを使ってアセンブラに入ることはしませんが、他のすべてが失敗した場合でも許容されます(ただし、ローカル変数 - 男性、異なる最適化レベルを使用する場合はどこにいるか分かりません)。
そして、この質問の目的は、を回避することです。 setjmp/longjmpアプローチです。
編集:私はかなりクールなアイディアを発見しましたが、完全には機能しません:gccの中
ネストされた関数を。彼らは何をすることができますか?
- ローカル変数へのアクセス権を持って、
- は、親関数でのgotoローカルラベルへの可能性を持っています!
- は、関数の呼び出し先によって呼び出すことができます。ただし、関数がネストされた関数へのポインタを渡すことを前提としているので、呼び出し先のポインタによって利用できます。何でもゼロコストをやってから私を防ぎ
ダウンサイドは:彼らは未使用なら
- 彼らも、-O0レベルで実行に最適化しています。これについて何かできますか?可能であれば、例外がスローされたときにシンボル名でアドレスを取得することができます。スローされていないときにノッキングを発生させる例外を実装する作業を行うだけです...
これは、この問題について若干異なるテイクのように思える:http://stackoverflow.com/questions/307610/how-do-exceptions-work-behind-the-scenes-in-c ...それC++での例外の動作を確認します。 C++が例外を実装する方法を理解すれば、Cプログラム用にその実装をコピーすることが可能かどうかを判断できます。 –
@MartinAtkins、私はg ++で例外がどのように実装されているかを少ししか認識していませんが、g ++の例外サポートが部分的にコンパイラとリンカ側にあるので、C言語で複製することは問題になりますツールを変更することなく。私はあなたがより多くのマナを得るために言及した話題を読むでしょう。 –
あなたは完全に間違っています、 '試して'/'キャッチ'構造はコストがかかります。最初に、 'try'は何らかの形でスタックとすべてのレジスタの位置をマークしなければならず、' catch'/'throw'は' try'コンテキストを1つずつunwindしなければなりません。 C 'setjmp' /' longjmp'には「同等の」機能があります。これはまったく同じですが、その周りには接着剤が少なくて済むだけです。 –