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

C++ setjmp/longjmp 異常處理機制實作範例解析

     編輯:關於C

程式碼概覽

展示使用 `setjmp` 與 `longjmp` 實作類似 try-catch 的非局部跳轉機制。包含一個捕獲點與兩個拋出點,演示堆疊展開行為。

核心元件

  • jmp_buf jmpbuffer:儲存堆疊環境(程式計數器、堆疊指針、暫存器等)
  • setjmp(jmpbuffer):保存當前環境,首次呼叫返回 0
  • longjmp(jmpbuffer, value):跳回 `setjmp` 點,使其返回 value(非 0)

完整程式碼

#include <iostream>
#include <setjmp.h>

using namespace std;

static jmp_buf jmpbuffer;

static void catch_exception(void);
static void raise_exception_1(void);
static void raise_exception_2(void);

int main(int argc, char *argv[]) {
    cout << "main()++" << endl;
    catch_exception();
    raise_exception_1();
    raise_exception_2();
    cout << "main()--" << endl;
    return 0;
}

static void catch_exception(void) {
    cout << "catch_exception()++" << endl;
    setjmp(jmpbuffer);  // 保存環境,第一次返回 0
    cout << "catch_exception()--" << endl;  // longjmp 返回後執行此行
}

static void raise_exception_1(void) {
    cout << "raise_exception_1()++" << endl;
    longjmp(jmpbuffer, 1);  // 跳回 catch_exception 的 setjmp 處
    cout << "raise_exception_1()--" << endl;  // 永遠不會執行
}

static void raise_exception_2(void) {
    cout << "raise_exception_2()++" << endl;
    longjmp(jmpbuffer, 2);  // 再次跳回
    cout << "raise_exception_2()--" << endl;  // 永遠不會執行
}

執行輸出與流程分析

輸出:
main()++
catch_exception()++
catch_exception()--
raise_exception_1()++
catch_exception()--
raise_exception_2()++
catch_exception()--
main()--

詳細流程追蹤

  1. main 呼叫 catch_exception
  2. catch_exception 執行 setjmp,儲存環境,返回 0,繼續印出 catch_exception()--
  3. 返回 main,呼叫 raise_exception_1
  4. raise_exception_1 印出 ++,執行 longjmp(jmpbuffer, 1)
  5. 跳轉發生:直接跳回 catch_exception 的 setjmp 行,此次 setjmp 返回 1
  6. 繼續執行 catch_exception 剩餘程式碼,印出 catch_exception()--
  7. 返回 main,呼叫 raise_exception_2
  8. 同理執行 longjmp(jmpbuffer, 2),setjmp 返回 2,印出 catch_exception()--
  9. 返回 main,印出 main()--,程式結束

關鍵特性解析

1. 堆疊展開行為

longjmp 會直接跳過 中間所有函數的返回流程,不會執行它們的清理程式碼(如解構子、finally 區塊)。這是與 C++ 例外機制的最大差異。

2. 返回值區分

  • setjmp 首次呼叫返回 0
  • 透過 longjmp(buf, val) 跳回時,setjmp 返回 val(非 0)
  • 可用此值判斷跳轉來源或錯誤代碼

3. 變數值的不確定性

C 標準規定:longjmp 後,非 volatile 的區域變數值為未定義行為。實務上需宣告為 volatile 確保一致性。

與 C++ 例外處理對比

特性setjmp/longjmpC++ try/catch
型別安全無(僅 int 值)完整型別系統
堆疊展開不執行解構子自動呼叫解構子
跨語言C/C++ 通用C++ 專用
效能極快(無 RTTI 開銷)較慢(需型別匹配)
標準庫支援<setjmp.h>語言內建

適用場景與警示

  • ✅ 適用:C 語言錯誤處理、嵌入式系統無例外支援、效能極度敏感路徑
  • ❌ 避免:C++ 專案(優先使用例外)、需 RAII 清理資源的場合、多執行緒環境
  • ⚠️ 嚴禁:在 C++ 中跨越有解構子的物件使用 longjmp,會導致資源洩漏

現代替代方案

C++17 起可使用 std::optional、std::expected(C++23)或錯誤碼回傳模式,避免非結構化跳轉。C 語言可考慮錯誤碼傳遞或編譯器擴展(如 GCC 的 cleanup 屬性)。

這個範例展示了底層控制流轉移機制,理解它有助於深入掌握執行時期堆疊管理,但在現代 C++ 開發中應謹慎使用。

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