1//所需頭文件 2#include 3 4intsetjump(jmp_bufbuf) 5voidlongjump(jmp_bufbuf,inti) 6
一些朋友該說了,“我從來不用這些跳轉(zhuǎn),免得出問題”。還是一直以來的那句話,“存在即合理”~
下面,我們來看看這兩個(gè)函數(shù)到底有什么可以推敲的東西。
1函數(shù)介紹
有研究過RTOS的朋友應(yīng)該對此不難理解,setjump主要是保存當(dāng)前函數(shù)調(diào)用點(diǎn)的現(xiàn)場環(huán)境(或者叫上下文),比如各種寄存器、堆棧等等,那么這些環(huán)境信息就記錄在jmp_buf所定義的buf中。
而當(dāng)我們在其他位置調(diào)用longjump函數(shù)就相當(dāng)于一個(gè)長跳轉(zhuǎn),傳入之前保存在buf中的信息,即可跳回到之前setjump所調(diào)用的位置(理解為恢復(fù)setjump所保存的環(huán)境也是可以的)。
所以,這里值得注意的是,不要率先調(diào)用longjump,否則程序不知道飛去哪里了。
其實(shí)跟RTOS中進(jìn)行任務(wù)切換有著異曲同工之妙。
你大概已經(jīng)注意到setjump有一個(gè)返回值,其主要分為兩種情況:
當(dāng)直接調(diào)用setjump函數(shù),則返回0;
當(dāng)調(diào)用longjump跳轉(zhuǎn)到setjump位置,則其返回longjump的第二個(gè)非零參數(shù)。
2跟goto有啥區(qū)別?
以前我也跟大家介紹過goto這匹野馬被馴服的方式(goto關(guān)鍵字你不知道的"那些事"(C語言提升)),在C語言中g(shù)oto只能實(shí)現(xiàn)函數(shù)內(nèi)部的跳轉(zhuǎn),無法實(shí)現(xiàn)跨函數(shù)的直接跳轉(zhuǎn),比如函數(shù)嵌套多層的跳轉(zhuǎn)等等。
當(dāng)然,你也可以借助goto與函數(shù)返回配合完成函數(shù)之間的跳轉(zhuǎn),不過那太麻煩了,所以這兩個(gè)庫函數(shù)該派上用場了。
這樣的跳轉(zhuǎn)太過于霸道,我們還是限制一下,切不可濫用,但其為異常處理代碼的模塊化帶來了福音,在非常多的開源庫中都有實(shí)際應(yīng)用。
下面給大家一個(gè)參考示例 ::
1#include 2#include 3 4jmp_bufmark; 5intfperr; 6voidfpcheck(void); 7 8/********************************************* 9*Function:main 10*Description:主任務(wù)函數(shù) 11*Note:(公眾號:最后一個(gè)bug) 12*********************************************/ 13intmain(void) 14{ 15intjmpret; 16 17//記錄異常代碼與正常代碼分支位置 18jmpret=setjmp(mark); 19if(jmpret==0) 20{ 21//正常用戶程序運(yùn)行 22 23} 24else 25{ 26//在正常用戶程序運(yùn)行過程中發(fā)生異常 27fpcheck(); 28} 29} 30/********************************************* 31*Function:Errorhandler 32*Description:異常中斷,在正常用戶程序運(yùn)行過程中發(fā)生異常處理函數(shù) 33*Note:(公眾號:最后一個(gè)bug) 34*********************************************/ 35voidErrorhandler(void) 36{ 37fperr=num; 38longjmp(mark,-1);//進(jìn)行長跳轉(zhuǎn)到異常處理 39} 40 41/********************************************* 42*Function:fpcheck 43*Description:故障處理函數(shù) 44*Note:(公眾號:最后一個(gè)bug) 45*********************************************/ 46voidfpcheck(void) 47{ 48 49switch(fperr) 50{ 51caseINVALID: 52//userCode 53break; 54 55caseOVERFLOW: 56//userCode 57break; 58 59caseZERODIVIDE: 60//userCode 61break; 62default: 63break; 64} 65 66}
3局限性
這組函數(shù)除了前面介紹的注意事項(xiàng),還有一個(gè)非常值得注意的點(diǎn)就是longjump的調(diào)用時(shí)機(jī)必須在setjump被調(diào)用的所在函數(shù)返回前。
因?yàn)閟etjump保存有堆棧信息等,一旦setjump的被調(diào)用的函數(shù)返回則相應(yīng)的環(huán)境會(huì)被釋放,導(dǎo)致longjump無法在恢復(fù)到setjump調(diào)用位置,可能造成程序奔潰。
最后
好了,今天就跟大家分享這么多了,這一塊還有一些東西可以挖掘,后面再整理一下分享出來。如果你覺得有所收獲,一定記得點(diǎn)個(gè)贊!
原文標(biāo)題:C語言中比goto還“霸道”的跳轉(zhuǎn)方式
文章出處:【微信公眾號:嵌入式ARM】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
審核編輯:湯梓紅
-
寄存器
+關(guān)注
關(guān)注
31文章
5253瀏覽量
119212 -
C語言
+關(guān)注
關(guān)注
180文章
7575瀏覽量
134154 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4237瀏覽量
61973 -
跳轉(zhuǎn)
+關(guān)注
關(guān)注
0文章
5瀏覽量
5927
原文標(biāo)題:C語言中比goto還“霸道”的跳轉(zhuǎn)方式
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論