首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言非本地跳轉:setjmp/longjmp 異常處理機制完整教學與實戰範例

     編輯:關於C語言

背景:為什麼需要 setjmp/longjmp?

  • goto 僅限函數內部
  • exit()/abort() 直接終止程式,無法清理資源
  • 需求:跨函數、跨層級錯誤恢復,類似其他語言的 try/catch

核心 API(<setjmp.h>)

int setjmp(jmp_buf env);        // 保存環境,首次返回 0,longjmp 返回時非 0
void longjmp(jmp_buf env, int val); // 恢復環境,使 setjmp 返回 val (val==0 則返回 1)

jmp_buf 為不透明型別,儲存:程式計數器、棧指標、框架指標、暫存器等。

基本範例:簡易 try/catch

#include <setjmp.h>
#include <stdio.h>

jmp_buf exception_env;

void risky_operation(int code) {
    if (code < 0) {
        printf("例外觸發: code=%d\n", code);
        longjmp(exception_env, code);  // 跳回 setjmp
    }
    printf("正常執行: code=%d\n", code);
}

int main() {
    switch (setjmp(exception_env)) {
        case 0:
            printf("try 區塊開始\n");
            risky_operation(1);
            risky_operation(-1);  // 觸發例外
            risky_operation(2);   // 不會執行
            break;
        case -1:
            printf("catch 區塊: 捕獲錯誤 -1\n");
            break;
        default:
            printf("catch 區塊: 其他錯誤 %d\n", setjmp(exception_env)); // 注意:這裡需儲存返回值
    }
    return 0;
}

關鍵限制與陷阱

限制說明後果
setjmp 所在函數已返回棧幀已銷毀,jmp_buf 失效長跳轉到無效棧 → 崩潰
變數修改未 volatile編譯器最佳化假設變數不變longjmp 後變數值舊
C++ 物件解構函數longjmp 不呼叫 destructor資源洩漏、不變量破壞
訊號處理函數中使用需 sigsetjmp/siglongjmp訊號遮罩未正確恢復

正確使用模式:錯誤碼傳遞

#define TRY do { jmp_buf _env; int _err = setjmp(_env); if (!_err) {
#define CATCH(err) } else { err = _err;
#define END_TRY } } while(0)

void foo() {
    int err;
    TRY {
        bar();          // 內部 longjmp(_env, ERR_CODE)
        baz();
    } CATCH(err) {
        fprintf(stderr, "錯誤 %d\n", err);
        // 清理資源
    } END_TRY;
}

實戰場景

  1. 解析器錯誤恢復:跳出深層遞迴下降
  2. 嵌入式系統:硬體故障跳回主迴圈重啟子系統
  3. 測試框架:TEST_ASSERT 失敗長跳轉回測試運行器
  4. 協程雛形:手動棧切換(需配合組合語言保存暫存器)

現代替代方案

  • C++:try/catch/throw(自動解構、型別安全)
  • C11:_Noreturn + 錯誤碼傳遞 + 清理函數
  • 庫支援:libexception, cmocka 測試框架內建

「setjmp/longjmp 是 C 語言的『核彈』:威力大、副作用強、非不得已勿用。」

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved