setjmp()*1とlongjmp()*2については大昔にちょっと聞いたくらいなのでどのような機能なのかすっかり忘れてしまっていたのでちょっと復習していたのでメモ。そもそも個人的に一番C言語の勉強に活用したと思うqmailにはsetjmp()もlongjmp()もでてこないので、なじみが無くても仕方がなかったりするわけですが。
とりあえずそれぞれの関数のプロトタイプはこんな感じ。
setjmp()を呼び出すと、jmpにコンテキストが記録される(戻り値は0)。コンテキストは主にレジスタの状態が記録された構造体(当然、保存される情報にはプログラムカウンタやスタックポインタが含まれている)。
後でjmpをlongjmp()に渡すとレジスタがjmpを呼んだ時点のものに書き換えられるので、プログラムの実行は強制的にsetjmp()を呼んだ部分から再開される(CPUにとっては現在の実行行はプログラムカウンタの値に過ぎないから)。
単に戻ってくるだけだと、記録するためのsetjmp()なのか、longjmp()によって実行が戻されてsetjmp()が呼ばれたように見えるのかが区別できなくて困るので、longjmpの第2引数にretを渡すとsetjmp()の戻り値がretになるようになっている。よって、retには0ではない数を指定する必要がある。
という風に理解しました。
例えば下記のようなプログラムを流すと下記のような感じになることは確認できました。
ちなみに、setjmp()しないで、longjmp()を呼ぶとプログラムが落ちます。
test.c
実行結果
困ってしまったのは、正直これの使いどころが良くわからないこと。
事例を調べていたらマクロを活用することによって「Omicron Cでtry-catchを使う」のように例外処理に使えるということはひとまずわかりました。ただ、コンパイラによる支援がまったく無いのでthrowをする可能性がある場所を、try~catchで囲み忘れるという事故が頻発しそうな気がします。こういうところから、Javaの検査例外の意義を再認識しましたが、今の自分が使うと収集がつかなくなりそうな気がします。このあたりはC言語バリバリの人に意見を聞きに行かないといけないかなぁ。
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/3630
コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。
OpenID を使ってログインすることができます。