Javaにはtry〜catch〜finallyの例外フローが存在するけどC言語には無い。でも実現することはできる。こんな感じで使える。
#include <stdio.h> #include <stdlib.h> #include "exception.h" /* 例外フローの定義 */ /* 例外を投げる関数 */ void sub1(EXCEPTION *e) { printf("sub1 start\n"); /* 表示される */ { int *t = malloc(sizeof(int)); if (t == NULL) exit(1); *t = 100; THROW(*e, t); /* Javaのthrow()に対応 */ } printf("sub1 end\n"); /* 表示されない */ } int main() { EXCEPTION e; TRY_BEGIN(e) { /* Javaのtryに対応 */ sub1(&e); } CATCH(e, int *a) { /* Javaのcatch()に対応 */ printf("catch %d\n", *a); /* 100と表示される */ free(a); } FINALLY { /* Javaのfinally()に対応 */ printf("finally\n"); /* 表示される */ } TRY_END /* 必ず必要 */ return 0; }
コメントのとおりJavaの例外フローと対応付けられる。これらの構文は次のようにsetjmp/longjmpをマクロで隠す形で定義している。
#ifndef __EXCEPTION_H__ #define __EXCEPTION_H__ #include <setjmp.h> typedef struct EXCEPTION { jmp_buf buf; void* value; } EXCEPTION; #define TRY_BEGIN(_E) { \ if ( setjmp(_E.buf) == 0) { #define CATCH(_E, _V) } else { \ _V = _E.value; #define FINALLY } \ { #define TRY_END } \ } #define THROW(_E, _V) { \ (_E).value = _V; \ longjmp((_E).buf, 1); \ } #endif
マクロ展開後の例を見ると理解しやすい。
void sub1(EXCEPTION *e) { printf("sub1 start\n"); /* 表示される */ { int *t = malloc(sizeof(int)); if (t == NULL) exit(1); *t = 100; { /* THROW */ (*e).value = t; /* THROW */ longjmp((*e).buf, 1); /* THROW */ } /* THROW */ } printf("sub1 end\n"); /* 表示されない */ } int main() { EXCEPTION e; { /* TRY_BEGIN */ if ( setjmp(e.buf) == 0) { /* TRY_BEGIN */ { sub1(&e); } } else { /* CATCH */ int *a = e.value; /* CATCH */ { printf("catch %d\n", *a); free(a); } } /* FINALLY */ { /* FINALLY */ { printf("finally\n"); } } /* TRY_END */ } /* TRY_END */ return 0; }
CATCH部分とFINALLY部分は省略しても構文として成立する。