VC++ Runtime Error 异常捕获之不挂的程序

  VC++ Runtime Error,  对不少朋友来说, 这是一个十分讨厌的错误提示,  您可能不知道如何着手调试: 产生这个错误的原因是什么? 确实只有知道了产生这个错误的直接原因, 才能去调试这个错误.

     刚碰到这个错误的时候, 是发生在视频解码的时候,  由于解码一直在工作状态,  所以我也不知道如何去调试, 当出现这个错误之后, 我们大多数时候就忽略了, 想从其他地方解决, 提高稳定性, 甚至怀疑解码器的稳定性;  后来, 我接触解码库之后,  开始调试这样的错误, 刚开始这样的错误并不容易重现, 往往要几个小时,  当这个错误重现之后,  程序还是在运行的, 只是其中的某一个线程中断了执行,  其中的这个线程弹出了 "VC++ Runtime Error" 这样的对话框, 如果你点击它, 则整个应用程序会直接退出. 为了调试, 我就不能点击这个对话框, 而是使用VC2005附件到进程, 然后再直接中断进程, 这个时候, 会有一个线程中断点就在对话框的消息循环中, 仔细查看堆栈, 发现了一个函数: msvcrt.dll!_abort() ,  到这里是时候查看MSDN了:

     

      函数名: abort

  功 能: 异常终止一个进程

  用 法: void abort(void);

      In a single or multithreaded Windows-based application, abort calls the Windows MessageBox function to create a message box to display the message with an OK button. When the user clicks OK, the program aborts immediately. 

    

    我们的程序就是基于WINDOS窗口的多线程应用程序,  调用了abort就会弹出对话框, 在release版本中, 就是一个确认对话框, 点击后程序就提示出错并退出.

    在正常的程序里, 我们是不会调用abort的, 除非是遇到了严重的, 不能恢复的错误.  那么到底这个abort是怎么被调用的呢, 我们自己写的代码显然是没有这个函数, 再仔细查看堆栈,  发现是在一个C语言版本的开源库中.  我们的程序是需要7*24小时运行的, 出现了解码异常应该要被我们忽略, 而不是应用程序崩溃. 开源的跨平台解码库是C语言写的,  在出现了严重错误时, 就直接abort这也是可以理解的, 不过, 这样的程序在我们的代码中显然要避免.  大哥, 现在都是什么年代了, 很多程序都是需要一直跑的, 我只好改的库的源代码来重新编译程序才能解决这个问题了, 该怎么改了, 如果去分析解码的逻辑, 我们没有专业的人才.  我想就干脆从abort函数这里入手, 直接返回成功值, 但是这样对解码逻辑影响更大, 可能导致更大的错误,  我想到了操作系统的异常机制, 由于我们是在WINDOWS平台上工作, 所以可以利用WINDOWS结构化异常,  我们可取消abort调用, 在这里我们使用代码产生一个结构化异常(SEH), 结构化异常分为硬件异常和软件异常, CPU可以检查到内存非法访问和除零错误等异常, 那么我们就将abort替换成除零语句, 比如 int i = 10/0;

     当程序执行到这里的时候,  CPU会捕捉这个异常, 并提示用户, 我们可以在调用解码函数的地方, 增加SEH捕捉代码, 来捕捉这个错误, 那么程序就能忽略这个错误并继续执行了. 后来的事实也证明了这个错误的忽略对程序并没有什么明显的影响.  怎么写这个捕捉代码呢, 操作系统支持的SEH捕捉代码块为 __try - __finally 块和 __try - __except 块, 而__try - __finnaly块就可以实现我们的功能.  写到这里, 可能有朋友要说了, 我们平时见的最多的是try-catch语句,  那么我要解释一下了, try-catch 是C++异常的处理方式,  而__try-__finnaly是操作系统SEH异常处理方式.  在C++语言的try-catch并不能捕捉操作系统结构化异常(比如CPU异常, 内存访问冲突, 除零错误等). C++异常只能捕获软件异常, 通常是调用throw而产生的异常, 比如MFC异常中常见的CException.  

    SEH异常和C++异常有本质的区别, SEH是操作系统提供的异常处理技术, 在任何支持该操作系统的编程语言中, 都可以使用, 而C++异常处理只能在编写C++代码时使用。然而, 应当知道WINDOWS的VC++编译器是使用操作系统结构化异常来实现C++异常的.  也就是说, C++的try块在VC++下编译时, 会变成__try块,  C++的catch块会变成SEH的 __except块: catch测试则变成SEH异常过滤器, catch中的代码则变为__except中的代码. 事实上, C++的throw块, 在编译的时候也会变成SEH的RaiseException函数调用, 由c++异常变为SEH异常.

    __finnally的好处在于, 有时更详细的异常信息对我们没有更大帮助, 我们只需要捕获到异常并忽略它。上面提到C++异常在VC++里被转换成SEH异常, 那么在VC下使用try-catch是否能捕获硬件异常呢? 比如我们常见的 0x0000000C 不可读或写.  VC++编译器已经提供了支持:

      try {;}  catch(...){;}   这样的语句就能够捕获所有异常:包括CPU异常, 以及C++异常;  不过需要注意的是, 在VC6.0中, 是默认支持的. 但是在VC2005中,  是默认不捕获CPU异常的. 区别在于一个C++编译选项/Eha , 只有这个选项打开才能用上面的try-catch()捕捉SEH异常.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值