<エラーコードとエラー処理>
ユーザーに処理の選択をさせている関係上、各関数内で様々なエラーが生じる可能性があります。例えば、データがないのに演算する、データがないのにセーブする、指定されたファイルが見つからない、などです。
エラーが生じた場合、ただプログラムを異常終了させるだけでは芸がありませんので、各関数が返すエラーコードに意味を持たせて、それに応じてmain関数内で適切なエラー処理をするようにするとよいでしょう。例えば、
#define NO_ERROR 0 /*
NO_ERRORは0 */
#define NO_DATA 1 /*
NO_DATAは1 */
#define SIZE_MISMATCH 2 /*
SIZE_MISMATCHは2 */
...
int main(void) {
...
err
= do_process(); /*
do_process関数を呼び出し、返却値(エラーコード)をerrに格納 */
...
if
(err != NO_ERROR) { /*
エラーがあったら */
switch
(err) { /*
エラーの種類で分岐してエラー処理 */
case
NO_DATA: ...
case
SIZE_MISMATCH:...
...
}
}
...
今回の課題では必要ないと思われますが、関数からの返却値に複数の意味を同時に持たせることも可能です。
#define
NO_ERROR 0 /*
00000000 */
#define
NO_FILE 1 /*
00000001 */
#define
NO_DATA 2 /*
00000010 */
#define
SIZE_MISMATCH 4 /*
00000100 */
#define
DIM_MISMATCH 8 /*
00001000 */
#define
ALLOC_FAILURE 16 /*
00010000 */
...
typedef
unsigned char ERROR; /* 符号なしchar型をERROR型として型定義 */
...
int
main(void) {
ERROR
err;
...
err
= some_function();
/*
some_funciton関数が返してきたエラーコードに従ってエラー処理 */
if
(err) {
if
(err & NO_FILE) {
...
}
if
(err & NO_DATA) {
...
}
if
(err & SIZE_MISMATCH) {
...
}
...
}
}
/*
関数some_functionの定義 */
/*
処理中に生じたエラーの情報を含むエラーコードを返す */
ERROR
some_function(void) {
ERROR
err = NO_ERROR; /*
返却(予定)値を0で初期化 */
if
(ファイルがなかったら)
err
|= NO_FILE; /*
errとNO_FILEの論理和(or)をerrに代入 */
if
(データがなかったら)
err
|= NO_DATA; /*
errとNO_DATAの論理和をerrに代入 */
if
(サイズが違ったら)
err
|= SIZE_MISMATCH; /* errとSIZE_MISMATCHの論理和をerrに代入 */
...
return
err; /*
呼び出し元にerrの値を返す */
}
この例では、返却値の各ビットを各エラーのフラグとして使っています。演算子&や|は、二つの数のビットごとの論理演算をするものです。それをふまえて、上の例の動作を考えてみて下さい。