終於搞明白了傳說中的setjmp,longjmp

2021-05-28 12:28:51 字數 2646 閱讀 1520

int setjmp(jmp_buf jmpb) 設定緩衝區來儲存堆疊的內容,將儲存的上下文存入程序的自身的資料空間(u區),並繼續在當前的上下文中執行,一旦碰到了longjmp,進城就從該程序 的u區,取出先前儲存的上下文,並恢復該程序的上下文為先前儲存的上下文。這時核心將使得程序從setjmp處執行(摘自:unix平台下c語言高階程式設計 指南)

setjmp和longjmp的函式原型在setjmp.h中。

函式原型:

int setjmp(jmp_buf envbuf);

setjmp函式用緩衝區envbuf儲存系統堆疊的內容,以便後續的longjmp函式使用。setjmp函式初次啟用時返回0值。

void longjmp(jmp_buf envbuf, int val);

longjmp函式中的引數envbuf是由setjmp函式所儲存的堆疊環境,引數val設定setjmp函式的返回值。longjmp函式本身是沒有返回值的,它執行後跳轉到儲存envbuf引數的setjmp函式呼叫,並由setjmp函式呼叫返回,此時setjmp函式的返回值就是val。

呼叫longjmp函式時不能使setjmp函式返回0,如果val為0,則setjmp函式返回1。longjmp函式從來不返回,因為它呼叫後就跳轉到setjmp函式儲存的堆疊處,恢復堆疊開始執行,所以longjmp函式不會返回。

void longjmp(jmp_buf jmpb, int val) 使程序返回到 setjmp處執行,retval 表示此時setjmp的返回值。

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

setjmp函式的返回值(直接返回時為0,longjmp跳轉返回時為longjmp的狀態引數retval,根據setjmp的返回值就可以判斷程式是 正常執行還是進行異常處理。

乙個setjmp可以有多個longjmp。 setjmp用於初始化跳轉變量(相當於打了乙個標記,宣告"用本跳轉變量的longjmp就跳到我這裡來啦"),longjmp用於跳轉。

setjmp可以多次返回,返回0表示初始化跳轉變量完成(也稱直接返回);返回其他值表示有函式呼叫了longjmp, 這時的返回值是longjmp設定的。 所以setjmp語句後有乙個switch-case塊,根據setjmp返回的不同值進行不同的處理。

setjmp()和longjum()是通過操縱過程活動記錄實現的。許多程式設計師新手(包括我-o-)並不知道這個強大的機制,因為它是c語言所獨有的。它們部分你不了c語言有限的轉移能力。這個兩個函式協同工作,如下所示:

*setjmp(jmp_buf j)必須首先被呼叫。它表示「使用變數j記錄現在的位置。函式返回零。」

*longjmp(jmp_buf j,int i)可以接著被呼叫。它表示「回到j所記錄的位置,讓它看上去像是從原來的setjmp()函式返回一樣。但是函式返回i,使**知道它實際上是通過longjmp()返回的。「坳口不?

*當使用longjmp()時,j的內容被銷毀。

*goto語句不能跳出c語言當前的函式(這也是「longjmp」取名的由來,它可以跳的很遠,甚至可以跳到其他檔案的函式中)。

*用longjmp只能跳回到曾經到過的地方。在setjmp的地方仍留有乙個過程活動記錄。從這個角度講,longjmp更像是「從何處阿里(come from)「而不是」往**去(go to)」。longjmp接受乙個額外的整型引數並返回它的值,這可以知道是由longjmp轉移到這裡的還是從上條語句執行後自然而然來的這裡的。

下面的**顯示了setjmp()和longjmp()一例。

#include

#include

jmp_buf buf;

banana()

int main()

else }

輸出結果如下:

first time throught

in banana()

back in main

需要注意的地方是:保證區域性變數在longjmp過程中一直保持它的值的唯一可靠方法是把它宣告為volatile(這使用於那些值在setjmp執行和longjmp返回之間會改變的變數)

另外乙個例子:

setjmp和longjmp函式使用示例:

#include

#include

static jmp_buf buf;

int main()

b = 5;

longjmp(buf, 1);

return 0; }

setjmp執行時返回0,執行b等於5,呼叫longjmp,跳轉到setjmp呼叫,setjmp返回1,列印b=5。

setjmp/longjmp最大的用途是錯誤恢復。只要還沒有從函式中返回,一旦發現乙個不可恢復的錯誤,可以把控制轉移到主輸入迴圈,並從那裡重新開始。有些人使用setjmp/longjmp從一串無數的函式呼叫中立即返回。還有些人用它們防範潛在的危險**。

setjmp/longjmp在c++中演變為更普通的異常處理機制"catch"和"throw"

傳說中的MTU

通訊術語 最大傳輸單元 maximum transmission unit,mtu 是指一種通訊協議的某一層上面所能通過的最大資料報大小 以位元組為單位 最大傳輸單元這個引數通常與通訊介面有關 網路介面卡 串列埠等 網際網路協議允許ip分片,這樣就可以將資料報分成足夠小的片段以通過那些最大傳輸單元小...

傳說中的truncate html

學習用rails做blog的時候要用到rails的truncate功能。h truncate post.content,100,問題來了,將html截斷後出現不完整的tag,導致後續的文章排版都錯亂了。本來考慮是不是自己寫乙個,正在思考思路,結果祭起google,好嗎,已經有牛人寫了 簡單記錄一下 ...

傳說中的分頁6

set quoted identifier off goset ansi nulls on go 名稱 分頁儲存過程 使用示例 exec sp pageindex from stusources 2,10 注意 目前還沒有對輸入的引數進行嚴格的驗證 預設為輸入都是合法有效的 alter proc s...