8.3.5 終了処理ルーチン

(1)

終了処理の登録と実行(atexit)ルーチンの作成例

終了処理の登録を行うライブラリatexit関数の作成法を示します。

atexit関数では、引数として渡された関数のアドレスを、終了処理のテーブルに登録します。登録された関数の個数が限界値(ここでは、登録できる個数を32個とします)を超えた場合、あるいは同じ関数が二度以上登録された場合はリターン値として0以外(ここでは1)を返します。そうでなければ0を返します。

以下にプログラム例を示します。

#include <stdlib.h> 
 
long _atexit_count=0 ; 
 
void (*_atexit_buf[32])(void) ; 
 
#ifdef __cplusplus
extern "C"
#endif 
long atexit(void (*f)(void)) 
{
    int i;
 
    for(i=0; i<_atexit_count ; i++)        // 既に登録されていないかチェックします
        if(_atexit_buf[i]==f)
            return 1; 
    if (_atexit_count==32)                 // 登録数の限界値をチェックします
        return 1; 
    else {
        _atexit_buf[_atexit_count++]=f;    // 関数のアドレスを登録します
        return 0;
    }
}

(2)

プログラムの終了(exit)ルーチンの作成例

プログラムの終了処理を行うライブラリexit関数の作成法を示します。プログラムの終了処理は、ユーザシステムによって異なりますので、以下のプログラム例を参考に、ユーザシステムの仕様に従った終了処理を作成してください。

exit関数は、引数として渡されたプログラムの終了コードに従ってプログラムの終了処理を行い、プログラム起動時の環境に戻ります。ここでは、終了コードを外部変数に設定して、main関数を呼び出す直前にsetjmp関数で退避した環境に戻ることによって実現します。プログラム実行前の環境に戻るためには、次の関数「callmain」を作成し、初期設定関数「PowerON_Reset_PC」から関数「main」を呼び出す代わりに、関数「callmain」を呼び出してください。

以下にプログラム例を示します。

#include <setjmp.h> 
#include <stddef.h>
 
extern long _atexit_count ; 
extern void (*_atexit_buf[32])(void) ;
#ifdef __cplusplus
extern "C"
#endif 
void _CLOSEALL(void);
int main(void);
extern jmp_buf _init_env ; 
int _exit_code ; 
 
#ifdef __cplusplus
extern "C"
#endif 
void exit(int code) 
{
    int i;
    _exit_code=code ;                           // _exit_codeにリターンコードを設定します
    for(i=_atexit_count-1; i>=0; i--)           // atexit関数で登録した関数を順次実行します
        (*_atexit_buf[i])();
    _CLOSEALL();                                // オープンした関数を全てクローズします
    longjmp(_init_env, 1) ;                     // setjmpで退避した環境にリターンします
}
#ifdef __cplusplus
extern "C"
#endif 
void callmain(void)
{
     // setjmpを用いて現在の環境を退避し、main関数を呼び出します
     if(!setjmp(_init_env))
         _exit_code=main();                     // exit関数からのリターン時には処理を終了します
}

(3)

異常終了(abort)ルーチンの作成例

異常終了の場合は、ご使用になっているユーザシステムの仕様に従って、プログラムを異常終了させる処理を行ってください。

C++プログラムを使用する場合、以下のときにもabort関数を呼び出します。

-

例外処理が正しく動作しなかった場合

-

純粋仮想関数自体をコールした場合

-

dynamic_castに失敗した場合

-

typeidに失敗した場合

-

クラス配列のdelete時に情報が取れなかった場合

-

クラスオブジェクトのデストラクタコール情報登録時に矛盾が発生した場合

 

以下、標準出力装置にメッセージを出力したあと、ファイルをクローズしてから無限ループしてリセットを待つプログラム例を示します。

#include <stdio.h>
#ifdef __cplusplus
extern "C"
#endif 
void _CLOSEALL(void);
#ifdef __cplusplus
extern "C"
#endif 
void abort(void)
{
        printf("program is abort !!\n");     // メッセージを出力します
        _CLOSEALL();                         // ファイルをクローズします
        while(1)    ;                        // 無限ループします
}