C言語のsetjmpとlongjmpについて。
libpngのサンプルでsetjmpが出てきてびっくりしたので挙動の確認をしておきたい。
setjmp /longjmp はセットで使う。
1.setjmpを一回呼び出すと、必ず0を返して戻ってくる。
2.その後、longjmpを呼び出すと、先ほどsetjmpが呼ばれた文まで戻り、再びsetjmpが呼ばれる。
3.その時のsetjmpの戻り値は、先に呼び出したlongjmpの第二引数となる
これだけだとgotoと似たようなものに思えるが、setjmpに対するlongjmpの呼び出しは、別の関数の中でもかまわない。関数を飛び越えて戻ってくる。
#include <csetjmp>
std::jmp_buf jmp_bf; int main() { int a = 3; int b = 0; if (setjmp(jmp_bf) == 0) { if (b == 0) { longjmp(jmp_bf, 1); } int c = a / b; printf("%d / %d = %d", a, b, c); } else { printf("0 divide error.\n"); } }
C言語には例外(try...catch...)がない。この、「関数を飛び越えて戻ってくる」という特性を生かして、C言語で例外処理に近いことができる。
つまり、以下のC++コードに近いことができる。
int main() { int a = 3; int b = 0; try{ int c = a / b; printf("%d / %d = %d", a, b, c); } catch(...) { std::cout << "0 divide error"; } std::cout << "Hello World!\n"; }
#include <iostream> #include <csetjmp> std::jmp_buf jmp_bf;
int divide(int a, int b) { if (b == 0) { longjmp(jmp_bf, 1);//mainのsetjmpまで飛ぶ } return a / b; }
int main() { int a = 3; int b = 0;
//初回は0
//longjmp後は1
if (setjmp(jmp_bf) == 0) { int c = divide(a,b); printf("%d / %d = %d", a, b, c); } else { printf("0 divide error.\n"); } }