今回の記事では例外処理についてお話していきます。手を抜きがちな例外処理ですが安全なソフトウェアを製作するうえで重要な部分になってくるのでおろそかにしないよう気を付けてくださいね。
前回の復習
前回の記事ではよく使われる標準関数についてまとめてみました。サンプルコードを試して身につけましょう!!
それぞれの関数について見直したい方はよく使う標準関数【C言語講座 #17】を参照してくださいね。
例外処理
まずは例外というものについて説明をします。
例えばmalloc関数でものすごい大量のメモリ領域を確保することを考えて見ましょう。この時メモリの空きが少なくてメモリが足りずに確保できない事態が起こったとします。そんなことはお構いなしにプログラムが処理を続けてデータが失われたなんてことになったら大変です。
このような実行してみたけどうまくいかなかった場合に備えて組んでおく処理のことを例外処理と呼びます。C言語の場合は他の言語のように特別な文法があるわけではなく、実行時にエラーが発生しそうな処理を逐一if文でNULLが返ってきていないかチェックをする必要があります(C言語の残念な部分ですね)。
試しに2つほどサンプルコードを見てみましょう。
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
fp = fopen("message.txt", "r");
if(!fp) {
/*エラーが発生した時の処理*/
fprintf(stderr, "cannot open file.\n"); //stderrにエラーのメッセージを渡す
exit(1); //エラーが発生したことを告げるため引数に1を渡してプログラムを終了している
}
fclose(fp);
return 0;
}
実行結果(エラー時)
cannot open file.
7行目から11行目にかけてのif文が例外処理に当たります。ifの条件式ではfpがNULLかどうかでfopenできたかを調べています。NULLが検出された場合はfprintf関数を用いて大域変数stderrにエラーメッセージを渡して、exit関数でプログラムを終了させるようにしています。(ちなみにexit関数を使うためにstdlib.hをインクルードしています)
大域変数というのはもともと用意されている特別な変数でstdinやstdoutなんかもそうです。stderrもそのひとつでエラーが発生したらfprintfを用いてエラーの簡単な説明を書くことが多いです。
実行結果はわざと例外処理を実行させた結果で、見ての通りエラー時のメッセージがちゃんと出力されています。
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 1000;
char *msg;
msg = (char *)calloc(n, sizeof(char));
if(!msg) {
/*エラーが発生した時の処理*/
fprintf(stderr, "cannot allocate memory.\n");
exit(1);
}
free(msg);
return 0;
}
実行結果(エラー時)
cannot allocate memory.
今度のサンプルコードは先ほど例で取り挙げたメモリ確保ができなかった場合の例外処理です。8行目から12行目にかけての部分が該当します。
2つほど例外処理のサンプルコードを眺めてもらった訳ですがどうですか?
もしかしたら発生するかもしれないエラーに備えて処理を分岐させて記述することこそが例外処理の本質です。
しかし突き詰めれば配列ひとつ作るのにもメモリ不足でエラーが発生するリスクがあり、そのすべてに対して例外処理を記述していたらソースコードの量が膨大になってしまいます。その結果、例外処理を除けば10行程度のソースコードが例外処理を書いたことで倍以上の長さになってしまうなんてことも大いに起こりえます。そして見通しが悪いコードになってしまったなんてことになりかねません。
これらの背景が例外処理を放置する現象に拍車をかけているわけですね。これらの問題に関してはエラー時の対応を自作関数化して処理をまとめたり、ファイル分割で見通しをよくするしかないと思います。
まとめ
今回の記事では例外処理について説明してきました。前回の記事までは何かを作るための構文や処理を勉強してきましたが、例外処理はそれらとは別でプログラムの安全性(エラー時の動作すら決めることで未定義な挙動を防ぐこと)を理念としていて何となく異質な感じがしたことでしょう。
プログラムが悪用されないように、エラーが発生した際には正しく終了するように例外処理を書くように心がけてくださいね。
最後まで記事を見ていただきありがとうございます。また別の記事でお会いできることを祈っております。