BLOGTIMES
2010/06/30

setjmp() と longjmp() と 例外処理

  c 
このエントリーをはてなブックマークに追加

setjmp()*1とlongjmp()*2については大昔にちょっと聞いたくらいなのでどのような機能なのかすっかり忘れてしまっていたのでちょっと復習していたのでメモ。そもそも個人的に一番C言語の勉強に活用したと思うqmailにはsetjmp()もlongjmp()もでてこないので、なじみが無くても仕方がなかったりするわけですが。

とりあえずそれぞれの関数のプロトタイプはこんな感じ。

int setjmp( jmp_buf jmp ); void longjmp( jmp_buf jmp, int ret );

setjmp()を呼び出すと、jmpにコンテキストが記録される(戻り値は0)。コンテキストは主にレジスタの状態が記録された構造体(当然、保存される情報にはプログラムカウンタやスタックポインタが含まれている)。

後でjmpをlongjmp()に渡すとレジスタがjmpを呼んだ時点のものに書き換えられるので、プログラムの実行は強制的にsetjmp()を呼んだ部分から再開される(CPUにとっては現在の実行行はプログラムカウンタの値に過ぎないから)。

単に戻ってくるだけだと、記録するためのsetjmp()なのか、longjmp()によって実行が戻されてsetjmp()が呼ばれたように見えるのかが区別できなくて困るので、longjmpの第2引数にretを渡すとsetjmp()の戻り値がretになるようになっている。よって、retには0ではない数を指定する必要がある。

という風に理解しました。

例えば下記のようなプログラムを流すと下記のような感じになることは確認できました。
ちなみに、setjmp()しないで、longjmp()を呼ぶとプログラムが落ちます

test.c

#include <stdio.h> #include <setjmp.h> static jmp_buf buf; void bar() { printf("bar called!\n"); longjmp(buf,2); } void foo() { printf("foo called!\n"); bar(); } int main() { int ret = setjmp(buf); if ( ret == 0 ) { foo(); } else { printf("ret:%d\n", ret); } return 0; }

実行結果

$ ./a.out foo called! bar called! ret:2

困ってしまったのは、正直これの使いどころが良くわからないこと。

事例を調べていたらマクロを活用することによって「Omicron Cでtry-catchを使う」のように例外処理に使えるということはひとまずわかりました。ただ、コンパイラによる支援がまったく無いのでthrowをする可能性がある場所を、try~catchで囲み忘れるという事故が頻発しそうな気がします。こういうところから、Javaの検査例外の意義を再認識しましたが、今の自分が使うと収集がつかなくなりそうな気がします。このあたりはC言語バリバリの人に意見を聞きに行かないといけないかなぁ。


トラックバックについて
Trackback URL:
お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/3630
Trackbacks
このエントリにトラックバックはありません
Comments
愛のあるツッコミをお気軽にどうぞ。[policy]
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントはありません
Comments Form

コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。

OpenID を使ってログインすることができます。

Identity URL: Yahoo! JAPAN IDでログイン