nptのドキュメントです。
参照元:ANSI Common Lisp npt
前へ:関数の登録
次へ:脱出の操作
LISP ABORT
とは、システムエラーによる強制終了のことです。
C言語のexit
関数を終了コード1
で呼び出し、プロセスを終了させます。
もし手動でabortを起こしたい場合は、次の関数を実行します。
(); lisp_abort
実行結果は次のようになります。
$ ./a.out
**************
LISP ABORT
**************
$ echo $?
1
$
実行例のように、LISP ABORT
という文言が出力された場合は、 プロセスが強制終了されたことを意味します。
確認している通り、そのときの終了コードは1
です。
終了時にメッセージを出力したい場合は下記の関数を使用します。
void lisp_abortf(const char *fmt, ...);
void lisp_abort8(const void *fmt, ...);
void lisp_abort16(const void *fmt, ...);
void lisp_abort32(const void *fmt, ...);
名前に8, 16, 32が付いている関数は、lisp_string8_
関数でメッセージを作成します。
format
を経由するため、Common Lispが動作している必要があります。
lisp_abortf
は、引数にprintf
の書式を受け取ります。
format
を経由しないため、Common Lispが動作している必要はありません。
ただしprintf
の引数にLispのオブジェクトを指定することはできません (できたとしても%p
くらいだと思います)。
lisp_abort
の挙動はハンドラーを登録することで変更できます。
例えば、下記のハンドラーを設定してみます。
void test_handler(void)
{
("Hello Handler.\n");
printf}
ハンドラーの登録はlisp_set_abort_handler
関数にて行います。
例えば次のようになります。
(test_handler);
lisp_set_abort_handler(); lisp_abort
実行結果を下記に示します。
$ ./a.out
Hello Handler.
**************
LISP ABORT
**************
$
ハンドラーが起動されたあと、LISP ABORT
が発生して プロセスが強制終了したことが分かります。
ハンドラーを登録したとしても、 そのまま終了した場合はLISP ABORT
が実行されます。
LISP ABORT
の捕捉LISP ABORT
は、setjmp
を使うことでプロセスを終了させることなく 処理を継続させることができます。
下記の命令を用いることで、捕捉と継続ができます。
lisp_set_abort_setjmp_handler
Lisp_abort_Begin
Lisp_abort_End
lisp_set_abort_setjmp_handler
は、補足用のハンドラーを設定します。
Lisp_abort_Begin
とLisp_abort_End
は、捕捉処理を囲むためのマクロです。
LISP ABORT
を補足する例を下記に示します。
int main(void)
{
();
lisp_set_abort_setjmp_handler{
Lisp_abort_Begin ("Start\n");
printf();
lisp_abort("End\n");
printf}
;
Lisp_abort_End
("Return\n");
printf
return 0;
}
実行結果は下記のとおりです。
$ ./a.out
Start
Return
$
実行結果ではStart
とReturn
が表示されており、 End
が表示されていないのがわかります。
lisp_abort
関数によりabortがが発生して、 処理がLisp_abort_End
までジャンプしたためです。
上記の方法だと、処理が普通に終わったものなのか、 あるいはLISP ABORT
が発生したものなのか区別がつきません。
そこで、次のように変更します。
void main_call(void)
{
("Start\n");
printf();
lisp_abort("End\n");
printf}
int main(void)
{
int finish;
();
lisp_set_abort_setjmp_handler= 0;
finish {
Lisp_abort_Begin ();
main_call= 1;
finish }
;
Lisp_abort_End
if (finish == 0)
("Lisp Abort\n");
printf
return 0;
}
変数finish
を用意し、Lisp_abort_Begin
の最後で 値が変更されていたら正常終了したとみなします。
実行結果を下記に示します。
$ ./a.out
Start
Lisp Abort
$
LISP ABORT
のハンドラーはsetjmp
が使われますが、 C++でコンパイルした場合はtry
/catch
に変更されます。
変更する理由はsetjmp
であればデストラクタが起動しないためです。
例として下記の文をC++で実行してみます。
class destruct
{
public:
() { printf("Constructor\n"); };
destruct~destruct() { printf("Destructor\n"); };
};
void main_call(void)
{
;
destruct x
("Start\n");
printf();
lisp_abort("End\n");
printf}
int main(void)
{
int finish;
();
lisp_set_abort_setjmp_handler= 0;
finish {
Lisp_abort_Begin ();
main_call= 1;
finish }
;
Lisp_abort_End
if (finish == 0)
("Lisp Abort\n");
printf
return 0;
}
実行例は下記のとおりです。
$ ./a.out
Constructor
Start
Destructor
Lisp Abort
$
この例ではsetjmp
ではなくtry
/catch
が使われているため、 デストラクタが起動しているのが確認できます。
このような挙動を好ましく思わない場合は、 コンパイル時にLISP_ABORT_SETJMP
をdefineすることで、 C++コンパイルでもsetjmp
を使用することができます。
上記の例文をsetjmp
で実行した結果を下記に示します。
$ ./a.out
Constructor
Start
Lisp Abort
$
lisp_abort
関数が実行されてると そのままLisp_abort_End
へと遷移しているため、 デストラクタが無視されているのがわかります。