最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語(yǔ)言異常處理機(jī)制案例講解

 更新時(shí)間:2021年07月02日 17:16:41   作者:youlin  
這篇文章主要介紹了C語(yǔ)言異常處理機(jī)制案例講解,本文講解了異常處理機(jī)制所用的函數(shù)和具體的代碼實(shí)現(xiàn)等,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

異常處理機(jī)制:setjmp()函數(shù)與longjmp()函數(shù)

  C標(biāo)準(zhǔn)庫(kù)提供兩個(gè)特殊的函數(shù):setjmp() 及 longjmp(),這兩個(gè)函數(shù)是結(jié)構(gòu)化異常的基礎(chǔ),正是利用這兩個(gè)函數(shù)的特性來(lái)實(shí)現(xiàn)異常。
所以,異常的處理過(guò)程可以描述為這樣:
首先設(shè)置一個(gè)跳轉(zhuǎn)點(diǎn)(setjmp() 函數(shù)可以實(shí)現(xiàn)這一功能),然后在其后的代碼中任意地方調(diào)用 longjmp() 跳轉(zhuǎn)回這個(gè)跳轉(zhuǎn)點(diǎn)上,以此來(lái)實(shí)現(xiàn)當(dāng)發(fā)生異常時(shí),轉(zhuǎn)到處理異常的程序上,在其后的介紹中將介紹如何實(shí)現(xiàn)。
setjmp() 為跳轉(zhuǎn)返回保存現(xiàn)場(chǎng)并為異常提供處理程序,longjmp() 則進(jìn)行跳轉(zhuǎn)(拋出異常),setjmp() 與 longjmp() 可以在函數(shù)間進(jìn)行跳轉(zhuǎn),這就像一個(gè)全局的 goto 語(yǔ)句,可以跨函數(shù)跳轉(zhuǎn)。
舉個(gè)例子,程序在 main() 函數(shù)內(nèi)使用 setjmp() 設(shè)置跳轉(zhuǎn),并調(diào)用另一函數(shù)A,函數(shù)A內(nèi)調(diào)用B,B拋出異常(調(diào)用longjmp() 函數(shù)),則程序直接跳回到 main() 函數(shù)內(nèi)使用 setjmp() 的地方返回,并且返回一個(gè)值。

-------------------------------------------------------------------------------------------------------------------------

jmp_buf 異常結(jié)構(gòu)

使用 setjmp() 及 longjmp() 函數(shù)前,需要先認(rèn)識(shí)一下 jmp_buf 異常結(jié)構(gòu)。jmp_buf 將使用在 setjmp() 函數(shù)中,用于保存當(dāng)前程序現(xiàn)場(chǎng)(保存當(dāng)前需要用到的寄存器的值),jmp_buf 結(jié)構(gòu)在 setjmp.h 文件內(nèi)聲明:

typedef struct
{
unsigned j_sp; // 堆棧指針寄存器
unsigned j_ss; // 堆棧段
unsigned j_flag; // 標(biāo)志寄存器
unsigned j_cs; // 代碼段
unsigned j_ip; // 指令指針寄存器
unsigned j_bp; // 基址指針
unsigned j_di; // 目的指針
unsigned j_es; // 附加段
unsigned j_si; // 源變址
unsigned j_ds; // 數(shù)據(jù)段
} jmp_buf;

jmp_buf 結(jié)構(gòu)存放了程序當(dāng)前寄存器的值,以確保使用 longjmp() 后可以跳回到該執(zhí)行點(diǎn)上繼續(xù)執(zhí)行。

-------------------------------------------------------------------------------------------------------------------------

  setjmp() 與 longjmp() 函數(shù)詳細(xì)說(shuō)明

setjmp() 與 longjmp() 函數(shù)原型如下:

  void _Cdecl longjmp(jmp_buf jmpb, int retval);

  int _Cdecl setjmp(jmp_buf jmpb);

_Cdecl 聲明函數(shù)的參數(shù)使用標(biāo)準(zhǔn)C的進(jìn)棧方式(由右向左)壓棧,_Cdecl 是C語(yǔ)言的一種調(diào)用約定,除此以外,PASCAL 也是調(diào)用約定之一。C標(biāo)準(zhǔn)調(diào)用約定(_Cdecl)所聲明的函數(shù)不自動(dòng)清除堆棧,這一事務(wù)由調(diào)用者自行負(fù)責(zé)——這也是C可以支持不固定個(gè)數(shù)的參數(shù)的原因。此外,這一調(diào)用約定將在函數(shù)名前添加一個(gè)下劃線字符,如某一函數(shù)聲明為:

int cdecl DoSomething(void);

編譯時(shí)將自動(dòng)為 DoSomething 加上下劃線前綴,即函數(shù)名變?yōu)椋? _DoSomething。

setjmp() 與 longjmp() 函數(shù)都使用了 jmp_buf 結(jié)構(gòu)作為形參,它們的調(diào)用關(guān)系是這樣的:

首先調(diào)用 setjmp() 函數(shù)來(lái)初始化 jmp_buf 結(jié)構(gòu)變量 jmpb,將當(dāng)前CPU中的大部分影響到程序執(zhí)行的寄存器的值存入 jmpb,為 longjmp() 函數(shù)提供跳轉(zhuǎn),setjmp() 函數(shù)是一個(gè)有趣的函數(shù),它能返回兩次,它應(yīng)該是所有庫(kù)函數(shù)中唯一一個(gè)能返回兩次的函數(shù),第一次是初始化時(shí),返回零,第二次遇到 longjmp() 函數(shù)調(diào)用后,longjmp() 函數(shù)使 setjmp() 函數(shù)發(fā)生第二次返回,返回值由 longjmp() 的第二個(gè)參數(shù)給出(整型,這時(shí)不應(yīng)該再返回零)。

在使用 setjmp() 初始化 jmpb 后,可以其后的程序中任意地方使用 longjmp() 函數(shù)跳轉(zhuǎn)會(huì) setjmp() 函數(shù)的位置,longjmp() 的第一個(gè)參數(shù)便是 setjmp() 初始化的 jmpb,若想跳轉(zhuǎn)回剛才設(shè)置的 setjmp() 處,則 longjmp() 函數(shù)的第一個(gè)參數(shù)是 setjmp() 所初始化的 jmpb 這個(gè)異常,這也說(shuō)明一件事,即 jmpb 這個(gè)異常,一般需要定義為全局變量,否則,若是局部變量,當(dāng)跨函數(shù)調(diào)用時(shí)就幾乎無(wú)法使用(除非每次遇到函數(shù)調(diào)用都將 jmpb 以參數(shù)傳遞,然而明顯地,是不值得這樣做的);longjmp() 函數(shù)的第二個(gè)參數(shù)是傳給 setjmp() 的第二次返回值,這在介紹 setjmp() 函數(shù)時(shí)已經(jīng)介紹過(guò)。

異常處理過(guò)程

先來(lái)對(duì)比(參考)一下 C++ 的異常處理,C++ 在語(yǔ)言層上便添加了異常處理機(jī)制,使用 try 塊來(lái)包含那些可能出現(xiàn)錯(cuò)誤的代碼,你可以在 try 塊代碼中拋出異常,C++ 使用 throw 來(lái)拋出異常。拋出異常后,將轉(zhuǎn)到異常處理程序中執(zhí)行,C++ 使用 catch 塊來(lái)包含那些處理異常的代碼,catch 塊可以接收不同類(lèi)型的異常。需要說(shuō)明的是,throw 一般不在 try 塊內(nèi)的代碼中拋出異常,try 塊內(nèi)的代碼調(diào)用了別的函數(shù),如函數(shù)A,函數(shù)A 又調(diào)用了函數(shù) B,throw 可以在函數(shù)B中拋出異常,或者更深的函數(shù)調(diào)用層,無(wú)論如何,只要有異常拋出,程序?qū)⑥D(zhuǎn)到 catch 處執(zhí)行。

C中如何實(shí)現(xiàn),或者明確地說(shuō)是模擬這一功能?

下面介紹的是一些簡(jiǎn)單的方法。

現(xiàn)在假設(shè) longjmp() 第二個(gè)值為1,即 setjmp() 第二次將返回1。我們使用一組簡(jiǎn)單的宏來(lái)替代 setjmp() 和 longjmp() 以便使用:

首先定義一個(gè)全局的異常:

jmp_buf Jump_Buffer;

因?yàn)?setjmp() 第一次調(diào)用初始化后返回0,第二次返回非0,可以這樣定義一個(gè)宏使得它功能接近于 C++ 的 try。

#define try if(!setjmp(Jump_Buffer))

當(dāng) setjmp() 函數(shù)第一次0 時(shí),取非為真,則執(zhí)行 try 塊內(nèi)的代碼,如:

try{

Test();

}

當(dāng)因?yàn)檎{(diào)用 longjmp() 拋出異常而導(dǎo)致 setjmp() 第二次返回時(shí)(程序?qū)?huì)轉(zhuǎn)到 setjmp() 函數(shù)處返回,這時(shí),這時(shí)應(yīng)該執(zhí)行的是異常處理代碼。longjmp() 使 setjmp() 函數(shù)返回非0,if(!setjmp(JumpBuffer)) 中將值取非則為假,是以,異常處理放在其后應(yīng)該使用一個(gè) else:

#define catch else

如此看起來(lái)便跟 C++ 相似了,setjmp() 函數(shù)的第二次返回導(dǎo)致 if() 中表達(dá)式值為假,剛好使 catch 塊得以執(zhí)行,如:

try{

Test();

}catch{

puts("Error");

}

實(shí)現(xiàn)如 C++ 的 throw 語(yǔ)句,事實(shí)上以宏替換 longjmp(jmp_buf, int) 的調(diào)用:

#define throw longjmp(Jump_Buffer, 1)

下面的例程解釋如何使用這些宏:
-------------------------------------------------------------------------------------------------------------------------

#include"stdio.h"
#include"conio.h"
#include"setjmp.h"
jmp_buf Jump_Buffer;
#define try if(!setjmp(Jump_Buffer))
#define catch else
#define throw longjmp(Jump_Buffer,1)
int Test(int T)
{
    if(T>100)
        throw;
    else
          puts("OK.");
    return 0;
}
int Test_T(int T)
{
    Test(T);
    return 0;
}
int main()
{
    int T;
    try{
          puts("Input a value:");
          scanf("%d",&T);
          T++;
          Test_T(T);
      } catch{
          puts("Input Error!");
      }
    getch();
    return 0;
}

到此這篇關(guān)于C語(yǔ)言異常處理機(jī)制案例講解的文章就介紹到這了,更多相關(guān)C語(yǔ)言異常處理機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Qt實(shí)現(xiàn)高準(zhǔn)確率的語(yǔ)音識(shí)別

    Qt實(shí)現(xiàn)高準(zhǔn)確率的語(yǔ)音識(shí)別

    Vosk是一個(gè)開(kāi)源的語(yǔ)音識(shí)別工具,支持中英文及多種語(yǔ)言,具備離線識(shí)別能力,且不依賴(lài)互聯(lián)網(wǎng),本文就來(lái)聊聊如何使用Vosk API在C++中進(jìn)行中英文識(shí)別吧
    2024-11-11
  • C/C++中使用列表框組件Qt?ListWidget

    C/C++中使用列表框組件Qt?ListWidget

    本文詳細(xì)講解了C/C++中使用列表框組件Qt?ListWidget的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • C++集體數(shù)據(jù)交換實(shí)現(xiàn)示例講解

    C++集體數(shù)據(jù)交換實(shí)現(xiàn)示例講解

    這篇文章主要介紹了C++集體數(shù)據(jù)交換實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-11-11
  • 深入解析C++中的虛函數(shù)與多態(tài)

    深入解析C++中的虛函數(shù)與多態(tài)

    對(duì)C++ 了解的人都應(yīng)該知道虛函數(shù)(Virtual Function)是通過(guò)一張?zhí)摵瘮?shù)表(Virtual Table)和一個(gè)指向虛函數(shù)表的指針(vptr)來(lái)實(shí)現(xiàn)的
    2013-09-09
  • C語(yǔ)言實(shí)現(xiàn)將字符和數(shù)字串到一起

    C語(yǔ)言實(shí)現(xiàn)將字符和數(shù)字串到一起

    今天小編就為大家分享一篇C語(yǔ)言實(shí)現(xiàn)將字符和數(shù)字串到一起,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-12-12
  • C++ 獲取URL內(nèi)容的實(shí)例

    C++ 獲取URL內(nèi)容的實(shí)例

    這篇文章主要介紹了C++ 獲取URL內(nèi)容的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • C++可調(diào)用對(duì)象callable object深入分析

    C++可調(diào)用對(duì)象callable object深入分析

    所謂的callable object,表示可以被某種方式調(diào)用其某些函數(shù)的對(duì)象。它可以是:一個(gè)函數(shù)、一個(gè)指向成員函數(shù)的指針、一個(gè)函數(shù)對(duì)象,該對(duì)象擁有operator()、一個(gè)lambda表達(dá)式,嚴(yán)格的說(shuō)它是一種函數(shù)對(duì)象
    2022-08-08
  • C++實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    C++實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C++ 多重繼承和虛擬繼承對(duì)象模型、效率分析

    C++ 多重繼承和虛擬繼承對(duì)象模型、效率分析

    本文簡(jiǎn)單介紹多態(tài)和多重繼承、虛擬繼承的基本概念。隨后重點(diǎn)分析了C++中對(duì)象模型之間的差異和運(yùn)行效率
    2014-08-08
  • 詳解C++的反調(diào)試技術(shù)與繞過(guò)手法

    詳解C++的反調(diào)試技術(shù)與繞過(guò)手法

    反調(diào)試技術(shù),惡意代碼會(huì)用它識(shí)別自身是否被調(diào)試,或者讓調(diào)試器失效,給反病毒工程師們制造麻煩,拉長(zhǎng)提取特征碼的時(shí)間線,本章將具體總結(jié)常見(jiàn)的反調(diào)試基礎(chǔ)的實(shí)現(xiàn)原理以及如何過(guò)掉這些反調(diào)試手段,從而讓我們能夠繼續(xù)分析惡意代碼
    2021-06-06

最新評(píng)論

湖北省| 虎林市| 林州市| 民丰县| 乐陵市| 瑞金市| 洛浦县| 梁山县| 丹寨县| 搜索| 长汀县| 桃园县| 平潭县| 四平市| 阳西县| 新营市| 高唐县| 屯昌县| 芜湖县| 林芝县| 建昌县| 潞西市| 梅河口市| 庆城县| 浪卡子县| 朝阳区| 永靖县| 石景山区| 丹凤县| 鹤岗市| 高平市| 万年县| 惠州市| 城固县| 区。| 汝南县| 水城县| 古田县| 汝城县| 商丘市| 汨罗市|