setjmp 和 longjmp 函式使用詳解

發表於2016-12-03

在網上看到的,覺得很有用,copy過來的。

非區域性跳轉語句—setjmp和longjmp函式。非區域性指的是,這不是由普通C語言goto,語句在一個函式內實施的跳轉,而是在棧上跳過若干呼叫幀,返回到當前函式呼叫路徑上的某一個函式中。

返回值:若直接呼叫則返回0,若從longjmp呼叫返回則返回非0值的longjmp中的val值

呼叫此函式則返回到語句setjmp所在的地方,其中env 就是setjmp中的 env,而val 則是使setjmp的返回值變為val。

當檢查到一個錯誤時,則以兩個引數呼叫longjmp函式,第一個就是在呼叫setjmp時所用的env,第二個引數是具有非0值的val,它將成為從setjmp處返回的值。使用第二個引數的原因是對於一個setjmp可以有多個longjmp。

上述程式將輸出:

注意到雖然first()子程式被呼叫,”first“不可能被列印。”main“被列印,因為條件語句if ( ! setjmp(buf) )被執行第二次。

使用setjmp和longjmp要注意以下幾點:

1、setjmp與longjmp結合使用時,它們必須有嚴格的先後執行順序,也即先呼叫setjmp函式,之後再呼叫longjmp函式,以恢復到先前被儲存的“程式執行點”。否則,如果在setjmp呼叫之前,執行longjmp函式,將導致程式的執行流變的不可預測,很容易導致程式崩潰而退出

2.  longjmp必須在setjmp呼叫之後,而且longjmp必須在setjmp的作用域之內。具體來說,在一個函式中使用setjmp來初始化一個全域性標號,然後只要該函式未曾返回,那麼在其它任何地方都可以通過longjmp呼叫來跳轉到 setjmp的下一條語句執行。實際上setjmp函式將發生呼叫處的區域性環境儲存在了一個jmp_buf的結構當中,只要主調函式中對應的記憶體未曾釋放 (函式返回時區域性記憶體就失效了),那麼在呼叫longjmp的時候就可以根據已儲存的jmp_buf引數恢復到setjmp的地方執行。

異常處理

在下例中,setjmp被用於包住一個例外處理,類似trylongjmp呼叫類似於throw語句,允許一個異常返回給setjmp一個異常值。下屬程式碼示例遵從1999 ISO C standardSingle UNIX Specification:僅在特定範圍內引用setjmp

  • ifswitch或它們的巢狀使用的條件表示式
  • 上述情況下與!一起使用或者與整數常值比較
  • 作為單獨的語句(不使用其返回值)

遵從上述規則使得建立程式環境緩衝區更為容易。更一般的使用setjmp可能引起未定義行為,如破壞區域性變數;編譯器被要求保護或警告這些用法。但輕微的複雜用法如switch ((exception_type = setjmp(env))) { }在文獻與實踐中是常見的,並保持了相當的可移植性。

相關文章