ProgrammingC開発者

C言語におけるエラーハンドリングはどのように実装されていますか?setjmp/longjmp、errno、およびエラーコードの返却の違いは何ですか?それぞれのアプローチをいつ使用すべきですか?

Hintsage AIアシスタントで面接を突破

答え

C言語には例外のための組み込みサポートはなく、エラーハンドリングは以下の方法で実装されます:

  1. エラーコードの返却(通常は関数の戻り値を通じて) 例:

    int read_file(const char *name) { FILE *f = fopen(name, "r"); if (!f) return -1; // エラー // ... fclose(f); return 0; // 成功 }
  2. グローバル変数errnoの使用 エラー発生時に標準関数はしばしばグローバル変数errnoを設定します。 例:

    FILE *fp = fopen("nofile", "r"); if (!fp) { perror("ファイルエラー"); // errnoが原因を特定 }
  3. setjmp/longjmp — 例外の"投げ"のメカニズム(実行コンテキストが保存され復元される) 複雑なケース(例えば、異なるレベル間の緊急終了)に使用されます。コードが複雑になり、リソースのリークを引き起こす可能性があるため、滅多に使われません。

    #include <setjmp.h> jmp_buf buf; if (setjmp(buf) == 0) { // ... longjmp(buf, 1); // if (setjmp(...)) に戻る } else { // エラーハンドリング }
  • エラーコードの返却 — 主な方法で、シンプルで安全です。
  • errno — ライブラリ関数に便利です。
  • setjmp/longjmp — 特定のケースに(複雑なライブラリやインタプリタ用)を使用します。

トリッキーな質問

次のコードは何を出力しますか?

#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のチェックが漏れていました。その結果、古い不正な値が保持され、間違った診断が行われました。


物語 チームは、多数のエラーコードの返却点を持つ複雑な構造を実装しましたが、返却値に関する規約(ゼロ/負の値)に従わず、いくつかのエラーが成功と解釈され、サービスの予測できない障害につながりました。