C言語には例外のための組み込みサポートはなく、エラーハンドリングは以下の方法で実装されます:
エラーコードの返却(通常は関数の戻り値を通じて) 例:
int read_file(const char *name) { FILE *f = fopen(name, "r"); if (!f) return -1; // エラー // ... fclose(f); return 0; // 成功 }
グローバル変数errnoの使用
エラー発生時に標準関数はしばしばグローバル変数errnoを設定します。
例:
FILE *fp = fopen("nofile", "r"); if (!fp) { perror("ファイルエラー"); // errnoが原因を特定 }
setjmp/longjmp — 例外の"投げ"のメカニズム(実行コンテキストが保存され復元される) 複雑なケース(例えば、異なるレベル間の緊急終了)に使用されます。コードが複雑になり、リソースのリークを引き起こす可能性があるため、滅多に使われません。
#include <setjmp.h> jmp_buf buf; if (setjmp(buf) == 0) { // ... longjmp(buf, 1); // if (setjmp(...)) に戻る } else { // エラーハンドリング }
次のコードは何を出力しますか?
#include <stdio.h> #include <setjmp.h> jmp_buf buf; void func() { longjmp(buf, 5); } int main() { int val = setjmp(buf); printf("val=%d ", val); if (val == 0) func(); return 0; }
答え:
setjmpは0を返し、関数funcが呼び出されます。longjmp(buf, 5)が実行され、実行がsetjmpに戻り、今度は5を返します。val=0
val=5
物語 あるライブラリでは、エラーメッセージのコールバックではなく、リターンコードのみでリソースをクリーンアップする手動メカニズムが実装されていました。しかし、プログラマはセットアップ/ロングジャンプを介したコールバックから返却時のエラー処理を忘れ、結果的にメモリリークとファイルロックが発生しました。
物語 ネットワークアプリケーションでは、ソケット操作後の
errnoのチェックが漏れていました。その結果、古い不正な値が保持され、間違った診断が行われました。
物語 チームは、多数のエラーコードの返却点を持つ複雑な構造を実装しましたが、返却値に関する規約(ゼロ/負の値)に従わず、いくつかのエラーが成功と解釈され、サービスの予測できない障害につながりました。