C异常处理实现精_第1页
C异常处理实现精_第2页
C异常处理实现精_第3页
C异常处理实现精_第4页
C异常处理实现精_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C 异常处理实现 : setjmp 和 longjmp此文为 internet 上选摘,过后我会用自己的理解补充此文。将对 setjmp 与 longjmp 的具体使用方法和适用的场合,进行一个非常全面的阐述。另外请特别注意, setjmp 函数与 longjmp 函数总是组合起来使用,它们是紧密相关的一对操 作,只有将它们结合起来使用, 才能达到程序控制流有效转移的目的, 才能按照程序员的预 先设计的意图,去实现对程序中可能出现的异常进行集中处理。与 goto 语句的作用类似,它能实现本地的跳转这种情况容易理解,不过还是列举出一个示例程序吧!如下:void main( void ) int

2、jmpret;jmpret = setjmp( 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"

3、n");break;case 2: printf( "Error 2"n");break;case 3:printf( "Error 3"n");break;default :printf( "Unknown Error"); break;exit(0);return;控制流是 进行了一个 ,这种情况其实也可以用 的方式,更为严谨一些,也更17-1 所示。上面的例程非常地简单,其中程序中使用到了异常处理的机制,这使得程序的代码非 常紧凑、清晰,易于理解。在程序运行过程中,当异常情况出现后, 本地跳转(进入

4、到异常处理的代码模块,是在同一个函数的内部) goto 语句来予以很好的实现,但是,显然 setjmp 与 longjmp 为友善。程序的执行流如图voidvoid ,!Hir二選入5字X辂滾港 理望玦“申'Jr仙却r印T 0 )这块地亩樹、'' M块、电逊燮拥-豊抡探护"的厂具r代例測h h_ 一 -抑淅岸序远呼仏 呈常冷理旃畫-銀蛍行tew% I总察为血肿¥萨:US上.呻诟罐久H;'旳如紹小卸墩?£盪住汉a鰹 /;护.常1L0:代叭凶扌JUi;/' j-ij-vuViriiLh-'p.启;如匕理1制人 如处ff鐵

5、奁.片撼的! ,:'4 I t L jir-.' w、?> .时它代砒的也i丁"抽畅fVM込是咅;r阮滴凤 觀i®rr蛊遥.mH: (''i '11 I k i/iifi 'r-L H' <vh'V用箭处覓廡璇 r 館 htjb" (jrapnet)fasv H ._prmgft 'Bftot IiVi"!: IsTpak:Cfleie 2 - prihLft nemf brent;孑;莎ihrFC *Err(*r AVTJ: tiiCEtik;dvfttiLll i U

6、fitnrfEttorH :brnskrmjiiiJGsetj mp与longjmp相结合,实现程序的非本地的跳转呵呵!这就是goto语句所不能实现的。也正因为如此,所以才说在C语言中,setjmp与longjmp 相结合的方式,它提供了真正意义上的异常处理机制。其实上一篇文章中的那个例程,已经演示了 longjmp函数的非本地跳转的场景。这里为了更清晰演示本地跳转与非本地跳转, 这两者之间的区别, 我 们在上面刚才的那个例程基础上,进行很小的一点改动,代码如下: void Fun c1()/其它代码的执行/判断程序远行中,是否出现错误,如果有错误,则跳转!if(1) longjmp (mar

7、k, 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/ 错误处理模

8、块 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 程序员提供了一种较完

9、善的异常处理编程的机制或手段。setjmp 和 longjmp 使用时,需要特别注意的事情1、setjmp 与 longjmp 结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp 函数,之后再调用 longjmp 函数, 以恢复到 先前被保存的 “程序执行点” 。否则,如果在 setjmp 调用之前,执行 longjmp 函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而 退出。 请看示例程序,代码如下: class Test public: Test() Test() obj;/注意,上面声明了一个全局变量obj void main( void ) int jmpret

10、;/ 注意,这里将会导致程序崩溃,无条件退出 Func1();while(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( "Erro

11、r 3"n"); break;default :printf( "Unknown Error"); break;exit(0);return;上面的程序运行结果,如下:构造对象Press any key to continue的确,上面程序崩溃了,由于在Func1() 函数内,调用了 longjmp ,但此时程序还没有调用 setjmp 来保存一个程序执行点。因此,程序的执行 流变的不可预测。这样导致的程序 后果是非常严重的,例如说,上面的程序中,有一个对象被构造了,但程序崩溃退出时,它 的析构函数并没有被系统来调用,得以 清除一些必要的资源。所以这样的

12、程序是非常危险 的。(另外请注意,上面的程序是一个 C+ 程序,所以大家演示并测试这个例程时,把源文 件的扩展名改为 xxx.cpp )。2、除了要求先调用 setjmp 函数,之后再调用 longjmp 函数(也即 longjmp 必须有对应 的 setjmp 函数)之外。另外,还有一个很重要的规则,那就是 longjmp 的调用是有一定域范 围要求的。这未免太抽象了,还是先看一个示例,如下: int Sub_Func()int jmpret, be_modify;be_modify = 0;jmpret = setjmp( mark ); if( jmpret = 0 )/ 其它代码的执行

13、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 :printf( "Unknown Error"); break;/注意这一语句,程序有条件地退出 if (be_modify=0) exit(0);return jmpret; void main( void

14、 ) Sub_Func();/ 注意,虽然 longjmp 的调用是在 setjmp 之后,但是它超出了 setjmp 的作用范围。 longjmp(mark, 1);如果你运行或调试(单步跟踪)一下上面程序,发现它真是挺神奇的,居然 longjmp 执 行时,程序还能够返回到 setjmp 的执行点,程序正常退出。但是这就说明了上面的这个例 程的没有问题吗?我们对这个程序小改一下,如下: int Sub_Func()/ 注意,这里改动了一点 int be_modify, jmpret;be_modify = 0;jmpret = setjmp( mark ); if( jmpret = 0

15、)/ 其它代码的执行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 :printf( "Unknown Error"); break;/注意这一语句,程序有条件地退出 if (be_modify=0) exit(0);return jmpret;void

16、 main( void ) Sub_Func();/ 注意,虽然 longjmp 的调用是在 setjmp 之后,但是它超出了 setjmp 的作用范围。 longjmp(mark, 1);运行或调试(单步跟踪)上面的程序,发现它崩溃了,为什么?这就是因为, “在调用 setjmp 的函数返回之前, 调用 longjmp ,否则结果不可预料” (这在上一篇文章中已经提到 过, MSDN 中做了特别的说明) 。为什么这样做会导致不可预料?其实仔细想想,原因也很 简单,那就是因为,当 setjmp 函数 调用时,它保存的程序执行点环境,只应该在当前的函 数作用域以内(或以后)才会有效。如果函数返回

17、到了上层(或更上层)的函数环境中,那 么 setjmp 保 存的程序的环境也将会无效,因为堆栈中的数据此时将可能发生覆盖,所以当 然会导致不可预料的执行后果。longjmp 之后,通过 setjmpMSDN 中做了特别的说明,3、不要假象寄存器类型的变量将总会保持不变。在调用 所返回的控制流中, 例程中寄存器类型的变量将不会被恢复。 上一篇文章中,这也已经提到过) 。寄存器类型的变量,是指为了提高程序的运行效率,变 量不被保存在内存中, 而是直接被保存在 寄存器中。 寄存器类型的变量一般都是临时变量, 在 C 语言中,通过 register 定义,或直接嵌入汇编代码的程序。这种类型的变量一般很少采 用,所以在使 用 setjmp 和 longjmp 时,基本上不用考虑到这一点。4、MSDN

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论