日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

setjmp与logjmp用法总结

發布時間:2023/12/10 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 setjmp与logjmp用法总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
setjmp/logjmp的最大用途是錯誤恢復,只要還沒有從主函數退出,一旦發現一個不可恢復的錯誤,可以把主控制轉移大主函數循環,并從那從新開始。使用時必須包含頭文件<setjmp.h>

setjmplongjmp結合使用時,它們必須有嚴格的先后執行順序,也即先調用setjmp函數,之后再調用longjmp函數,以恢復到先前被保存的程序執行點。(從哪兒來,回哪兒去)否則,如果在setjmp調用之前,執行longjmp函數,將導致程序的執行流變的不可預測,很容易導致程序崩潰而退出。


? setjmplogjmp的使用場合:

1.人們對于goto語句的忌諱,很多的專業書籍以及專業人士號召限制goto語句的使用,此時,setjmplongjmpgoto語句有了很好的替代作用.
2.goto
語句有一個局限性,它只能在函數內部跳轉.setjmplongjmp可以在整個程序全局中跳轉,實現"長跳轉",彌補了goto功能的局限
.
3.
使用setjmplongjmp可以捕捉程序中的異常,并采取異常處理機制.



一個例子? 使用setjmp,longjmp處理異常.


? 1 #include<stdio.h>
? 2 #include<setjmp.h>
? 3 jmp_buf jumper;
? 4 void exception();
? 5 int deal_exception();
? 6
? 7 main()
? 8 {
? 9???????? int value;
?10???????? int i=0;
?11
?12???????? value=setjmp(jumper);
?13???????? if(0==value){
?14???????????????? exception();
?15???????? }
?16???????? else{
?17???????????????? switch(value)
?18???????????????? {
?19???????????????????????? case 1:
?20???????????????????????????????? printf("解決異常情況[%d]\n",value);
?21???????????????????????????????? break;
?22???????????????????????? case 2:
?23????????????????????????????????? printf("解決異常情況[%d]\n",value);
?24????????????????????????????????? break;
?25???????????????????????? case 3:
?26????????????????????????????????? printf("解決異常情況[%d]\n",value);
?27????????????????????????????????? break;
?28
?29???????????????????????? default:
?30
?31????????????????????????????????? break;
?32???????????????? }
?33???????? }
?34 }
?35 void exception()
?36 {
?37???????? int _err_no;
?38???????? if(_err_no=3){
?39???????????????? printf("出現異常情況[%d]\n",_err_no);
?40???????????????? longjmp(jumper,_err_no);
?41???????? }
?42???????? return;
?43 }

結果:
[root@localhost test]# gcc error.c
[root@localhost test]# ./a.out
出現異常情況[3]
解決異常情況[3]
[root@localhost test]#

C語言的try and catch機制

C語言具有的類似try and catch機制,unix下機制也相同。

VC例子:

#include <stdio.h>

#include <setjmp.h>

jmp_buf mark;? // 保存stack環境的變量

?

void main(void)

{

int jmpret;

int result;

jmpret = setjmp( mark );? @1@ // 保存當前stack環境到mark變量

if( jmpret == 0 )

{

scanf("%d",&result);

if(result<0) {

longjmp( mark, -1 );? // 發生錯誤,恢復保存的stack環境,執行跳轉到@1@處,jmpret的值為-1

return;

???? // 此語句永遠不被執行

} else {

printf("Normal!");

return;

}

} else {

// 錯誤處理

printf("An exception occured!");

}

}

?

?

longjmp在Standard C中的說明:

1.用longjmp跳轉時保證靜態變量有正確的值

2.auto變量只保證擁有volatile類型和在setjmp和longjmp之間沒有改變的值。

解釋:

1.靜態變量保持為在longjmp調用時的值

2.在setjmp和longjmp之間沒有改變的值仍然是原值,(很簡單,因為從來就沒有改變過)

對于一些auto-nonvolatile的值,可能在循環中,編譯器為了優化性能,用寄存器來緩存,longjmp跳轉時沒有賦值,用volatile修飾能阻止編譯器優化。

這兩個函數都要包含頭文件setjmp.h。而且它們在處理出現在深層函數嵌套的錯誤情況時很有用處。
??? setjmp這個函數很有意思,雖然是一個函數,可是卻可以返回兩個不同的值。當第一次直接調用setjmp時,返回值為0。當從longjmp函數返回時,setjmp函數的返回值為longjmp的第二個參數的值。
??? 那么在什么地方調用setjmp呢?我們希望當從longjmp函數返回時,程序從哪里接著開始運行,我們就在哪里調用setjmp。看個小實例,你就明白是怎么回事了。

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

??? jmp_buf ebuf;
??? void f2(void);
?? int main(void)
?? {
???? int i;
???? printf("1");
???? i=setjmp(ebuf);
???? if(i==0)????????????????????????????????????????????? //第一次執行到這里時,值為0,所以接下來執行f2()
???? {
?? f2();
?? printf("This will not be printed.");
???? }
???? printf("%d",i);?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? //由于從longjmp返回時,i=3,不執行if,所以執行該行
???? return 0;
}
?? void f2(void)
{
?? printf("2");?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??
?? longjmp(ebuf,3);?? ?? ?? ?? ?? ?? ?? //longjmp函數返回,回到setjmp的位置,使得setjmp返回值為3
}
??? 函數最后的執行結果為123,嘻嘻。

????? longjmp注意:
  1.不要假象寄存器類型的變量將總會保持不變。在調用longjmp之后,通過setjmp所返回的控制流中,例程中寄存器類型的變量將不會被恢復。
  2.不要使用longjmp函數來實現把控制流,從一個中斷處理例程中傳出,除非被捕獲的異常是一個浮點數異常。在后一種情況下,如果程序通過調用 _fpreset函數,來首先初始化浮點數包后,它是可以通過longjmp來實現從中斷處理例程中返回。
  3. 在C++程序中,小心對setjmp和longjmp的使用,應為setjmp和longjmp并不能很好地支持C++中面向對象的語義。因此在C++程序中,使用C++提供的異常處理機制將會更加安全。把setjmp和longjmp組合起來,原來它這么厲害

使用setjmp時必須使用頭文件setjmp.h。

#include "setjmp.h"

jmp_buf jmpbuffer;
?
int setjmp(jmp_buf jmpbuffer);
void longjmp(jmp_buf jumpbuffer, int retval);
?
其中 jmpbuffer 是相關的程序棧的環境上下文。
初始化jmpbuffer之后, setjmp第一次調用的時候會返回 0。
longjmp跳轉到setjmp處,其中第二個參數retval就是傳遞給setjmp, 作為setjmp的返回值。但是需要主要的是,如果retval設置為0, 即這樣調用的時候 longjmp(jumpbuffer, 0), setjmp會返回1。

函數setjmp()的行為很特別,如果直接調用它,它便將所有與當前處理器相關的狀態信息(比如指令指針的內容,棧指針等)保存到jmp_buf中并返回0。在這種情況下,它的表現與一個普通的函數一樣。然而,如果使用同一個jmp_buf調用longjmp(),則函數返回時就好像剛從setjmp()中返回時一樣-----又回到剛剛從setjmp()返回的地方。這一次,返回值是調用longjmp()時所使用的第二個參數,因此可通過這個值判斷程序是從longjmp()返回的

總結

以上是生活随笔為你收集整理的setjmp与logjmp用法总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。