




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、C異常處理實現: setjmp和longjmp 此文為internet上選摘,過后我會用自己的理解補充此文。- 將對setjmp與longjmp的具體使用方法和適用的場合,進行一個非常全面的闡述。另外請特別注意,setjmp函數與longjmp函數總是組合起來使用,它們是緊密相關的一對操作,只有將它們結合起來使用,才能達到程序控制流有效轉移的目的,才能按照程序員的預先設計的意圖,去實現對程序中可能出現的異常進行集中處理。與goto語句的作用類似,它能實現本地的跳轉這種情況容易理解,不過還是列舉出一個示例程序吧!如下: void main( void )int jmpret;jmpret = s
2、etjmp( mark );if( jmpret = 0 )/ 其它代碼的執行/ 判斷程序遠行中,是否出現錯誤,如果有錯誤,則跳轉!if(1) longjmp(mark, 1);/ 其它代碼的執行/ 判斷程序遠行中,是否出現錯誤,如果有錯誤,則跳轉!if(2) longjmp(mark, 2);/ 其它代碼的執行/ 判斷程序遠行中,是否出現錯誤,如果有錯誤,則跳轉!if(-1) longjmp(mark, -1);/ 其它代碼的執行else/ 錯誤處理模塊switch (jmpret)case 1:printf( "Error 1"n");break;case 2
3、:printf( "Error 2"n");break;case 3:printf( "Error 3"n");break;default :printf( "Unknown Error");break;exit(0);return; 上面的例程非常地簡單,其中程序中使用到了異常處理的機制,這使得程序的代碼非常緊湊、清晰,易于理解。在程序運行過程中,當異常情況出現后,控制流是 進行了一個本地跳轉(進入到異常處理的代碼模塊,是在同一個函數的內部),這種情況其實也可以用goto語句來予以很好的實現,但是,顯然setjm
4、p與 longjmp的方式,更為嚴謹一些,也更為友善。程序的執行流如圖17-1所示。setjmp與longjmp相結合,實現程序的非本地的跳轉呵呵!這就是goto語句所不能實現的。也正因為如此,所以才說在C語言中,setjmp與longjmp相結合的方式,它提供了真正意義上的異常處 理機制。其實上一篇文章中的那個例程,已經演示了longjmp函數的非本地跳轉的場景。這里為了更清晰演示本地跳轉與非本地跳轉,這兩者之間的區別,我 們在上面剛才的那個例程基礎上,進行很小的一點改動,代碼如下:void Func1()/ 其它代碼的執行/ 判斷程序遠行中,是否出現錯誤,如果有錯誤,則跳轉!if(1) l
5、ongjmp(mark, 1);void Func2()/ 其它代碼的執行/ 判斷程序遠行中,是否出現錯誤,如果有錯誤,則跳轉!if(2) longjmp(mark, 2);void Func3()/ 其它代碼的執行/ 判斷程序遠行中,是否出現錯誤,如果有錯誤,則跳轉!if(-1) longjmp(mark, -1);void main( void )int jmpret;jmpret = setjmp( mark );if( jmpret = 0 )/ 其它代碼的執行/ 下面的這些函數執行過程中,有可能出現異常Func1();Func2();Func3();/ 其它代碼的執行else/ 錯誤
6、處理模塊switch (jmpret)case 1:printf( "Error 1"n");break;case 2:printf( "Error 2"n");break;case 3:printf( "Error 3"n");break;default :printf( "Unknown Error");break;exit(0);return;回顧一下,這與C+中提供的異常處理模型是不是很相近。異常的傳遞是可以跨越一個或多個函數。這的確為C程序員提供了一種較完善的異常處理編程的機
7、制或手段。setjmp和longjmp使用時,需要特別注意的事情1、setjmp與longjmp結合使用時,它們必須有嚴格的先后執行順序,也即先調用setjmp函數,之后再調用longjmp函數,以恢復到 先前被保存的“程序執行點”。否則,如果在setjmp調用之前,執行longjmp函數,將導致程序的執行流變的不可預測,很容易導致程序崩潰而退出。 請看示例程序,代碼如下:class Testpublic:Test() Test() obj; /注意,上面聲明了一個全局變量objvoid main( void )int jmpret;/ 注意,這里將會導致程序崩潰,無條件退出Func1();w
8、hile(1);jmpret = setjmp( mark );if( jmpret = 0 )/ 其它代碼的執行/ 下面的這些函數執行過程中,有可能出現異常Func1();Func2();Func3();/ 其它代碼的執行else/ 錯誤處理模塊switch (jmpret)case 1:printf( "Error 1"n");break;case 2:printf( "Error 2"n");break;case 3:printf( "Error 3"n");break;default :print
9、f( "Unknown Error");break;exit(0);return;上面的程序運行結果,如下:構造對象Press any key to continue 的確,上面程序崩潰了,由于在Func1()函數內,調用了longjmp,但此時程序還沒有調用setjmp來保存一個程序執行點。因此,程序的執行 流變的不可預測。這樣導致的程序后果是非常嚴重的,例如說,上面的程序中,有一個對象被構造了,但程序崩潰退出時,它的析構函數并沒有被系統來調用,得以 清除一些必要的資源。所以這樣的程序是非常危險的。(另外請注意,上面的程序是一個C+程序,所以大家演示并測試這個例程時,把源
10、文件的擴展名改為 xxx.cpp)。2、除了要求先調用setjmp函數,之后再調用longjmp函數(也即longjmp必須有對應的setjmp函數)之外。另外,還有一個很重要的規則,那就是longjmp的調用是有一定域范圍要求的。這未免太抽象了,還是先看一個示例,如下:int Sub_Func()int jmpret, be_modify;be_modify = 0;jmpret = setjmp( mark );if( jmpret = 0 )/ 其它代碼的執行else/ 錯誤處理模塊switch (jmpret)case 1:printf( "Error 1"n&qu
11、ot;);break;case 2:printf( "Error 2"n");break;case 3:printf( "Error 3"n");break;default :printf( "Unknown Error");break;/注意這一語句,程序有條件地退出if (be_modify=0) exit(0);return jmpret;void main( void )Sub_Func();/ 注意,雖然longjmp的調用是在setjmp之后,但是它超出了setjmp的作用范圍。longjmp(mark
12、, 1);如果你運行或調試(單步跟蹤)一下上面程序,發現它真是挺神奇的,居然longjmp執行時,程序還能夠返回到setjmp的執行點,程序正常退出。但是這就說明了上面的這個例程的沒有問題嗎?我們對這個程序小改一下,如下:int Sub_Func()/ 注意,這里改動了一點int be_modify, jmpret;be_modify = 0;jmpret = setjmp( mark );if( jmpret = 0 )/ 其它代碼的執行else/ 錯誤處理模塊switch (jmpret)case 1:printf( "Error 1"n");break;ca
13、se 2:printf( "Error 2"n");break;case 3:printf( "Error 3"n");break;default :printf( "Unknown Error");break;/注意這一語句,程序有條件地退出if (be_modify=0) exit(0);return jmpret;void main( void )Sub_Func();/ 注意,雖然longjmp的調用是在setjmp之后,但是它超出了setjmp的作用范圍。longjmp(mark, 1); 運行或調試(單
14、步跟蹤)上面的程序,發現它崩潰了,為什么?這就是因為,“在調用setjmp的函數返回之前,調用longjmp,否則結果不可預料” (這在上一篇文章中已經提到過,MSDN中做了特別的說明)。為什么這樣做會導致不可預料?其實仔細想想,原因也很簡單,那就是因為,當setjmp函數 調用時,它保存的程序執行點環境,只應該在當前的函數作用域以內(或以后)才會有效。如果函數返回到了上層(或更上層)的函數環境中,那么setjmp保 存的程序的環境也將會無效,因為堆棧中的數據此時將可能發生覆蓋,所以當然會導致不可預料的執行后果。 3、不要假象寄存器類型的變量將總會保持不變。在調用longjmp之后,通過setjmp所返回的控制流中,例程中寄存器類型的變量將不會被恢復。 (MSDN中做了特別的說明,上一篇文章中,這也已經提到過)。寄存器類型的變量,是指為了提高程序的運行效率,變量不被保存在內存中,而是直接被保存在 寄存器中。寄存器類型的變量一般都是臨時變量,在C語言中,通過register定義,或直接嵌入匯編代碼的程序。這種類型的變量一般很少采用,所以在使 用setjmp和longjmp時,基本上不用考慮到這一點。4、MSDN中還做了特別的說
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 合伙人入股協議書3篇
- 共建和諧供應商反恐行動3篇
- 年人才輸送協議書范文3篇
- 保險退保委托書中的保險條款解讀3篇
- 兼職教師聘用協議書范文3篇
- 化工產品市場分析勞動合同格式2篇
- 地皮轉讓合同3篇
- 紙板容器研發成果轉化考核試卷
- 電力設備狀態維修策略與應用考核試卷
- 育苗專家系統開發與應用考核試卷
- GB/T 9775-2008紙面石膏板
- GB/T 12604.4-2005無損檢測術語聲發射檢測
- GB/T 1229-2006鋼結構用高強度大六角螺母
- 多中心結直腸癌臨床研究生物樣本庫信息系統的建設與管理
- 消防管道支架制作安裝標準2017.噴淋
- 曲柄連桿機構拆裝教學教材課件
- 合格供應商年度評審計劃
- 培訓考試匯總金屬膠接工藝簡介
- Q-RJ 557-2017 航天型號產品禁(限)用工藝目錄(公開)
- ZGM95G-1型中速輥式磨煤機使用和維護說明書
- SZ系列GPS標準時間同步鐘使用說明
評論
0/150
提交評論