如何把SEH类型的系统异常转化为C++类型的异常

2023-12-16 21:32
文章标签 c++ 类型 系统 异常 转化 seh

本文主要是介绍如何把SEH类型的系统异常转化为C++类型的异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为什么要 把 SEH 类型的系统异常转化为 C++ 类型的异常?

做一件事情之前,我们最好要搞清为什么!“十万个为什么” 可曾造就了多少顶级奇才!呵呵! WHY? ? WHY ? WHY ?这对任何一个人来说,都绝对是个好习惯,阿愚同学就一直把这个当“宝贝”。那么,究竟 为什么要 把 SEH 类型的系统异常转化为 C++ 类型的异常?朋友们,大家都想想,整理整理自己的意见和想法。这里,阿愚给出它个人的理解,如下:

• 首先是由于我们在编程时,仍然最好遵循 MSDN 给出的建议和忠告(“ C 程序中使用 try-except 和 try-finally ;而 C++ 程序则应该使用 try-catch ”)。但是,为了提高程序的可靠性(防止意外系统异常的出现,而导致的程序无规则崩溃现象),我们还必须要求在 C++ 程序中,使用 try-catch 模型 能够捕获并 处理系统异常, 这在第 3 集的文章中曾详细讨论过了它, 那就是它只能采用 catch(…) 语法来捕获 SEH 类型的系统异常。 catch(…) 的使用 虽然一定程度上提高了程序的可靠性,但是,“异常发生时的许多相关信息”它却什么也没有提供给程序员(包括何种类型的系统异常,出现的地点,以及其它有关 异常的信息等等)。因此,我们需要一种有效途径,来把 SEH 类型的系统异常转化为 C++ 类型的异常?这无疑也就提供了一种在 C++ 异常处理模型中,不仅能够处理系统异常,而且还能够获取有关 SEH 类型系统异常中的许多详细信息的手段。

• 其次就是,阿愚多次阐述过, C++ 异常处理是和面向对象紧密联系的(它二位可是“哥俩好”),因此,如果把 SEH 类型的系统异常统一到面向对象体系结构设计的“异常分类”中去,那对程序员而言,岂不是妙哉!美哉!该解决方案真所谓是,即提高了可靠性;又不失优雅!

如何实现 把 SEH 类型的系统异常转化为 C++ 类型的异常?

虽然说把 SEH 类型的系统异常转化为 C++ 类型的异常,给 C++ 程序员带来的是好处多多,但是实现起来并不复杂,因为系统底层和 VC 运行库已经为我们铺路搭桥了,也即我们可以通过 VC 运行库中的“ _ set_se_translator ”函数来轻松搞定它。 MSDN 中对它解释如下:

Handles Win32 exceptions (C structured exceptions) as C++ typed exceptions.

typedef void (*_se_translator_function)( unsigned int, struct _EXCEPTION_POINTERS* );

_se_translator_function _set_se_translator( _se_translator_function se_trans_func );

The _set_se_translator function provides a way to handle Win32 exceptions (C structured exceptions) as C++ typed exceptions. To allow each C exception to be handled by a C++ catch handler, first define a C exception “wrapper” class that can be used, or derived from, in order to attribute a specific class type to a C exception. To use this class, install a custom C exception translator function that is called by the internal exception-handling mechanism each time a C exception is raised. Within your translator function, you can throw any typed exception that can be caught by a matching C++ catch handler.

To specify a custom translation function, call _set_se_translator with the name of your translation function as its argument. The translator function that you write is called once for each function invocation on the stack that has try blocks. There is no default translator function.

In a multithreaded environment, translator functions are maintained separately for each thread. Each new thread needs to install its own translator function. Thus, each thread is in charge of its own translation handling.

The se_trans_func function that you write must take an unsigned integer and a pointer to a Win32 _EXCEPTION_POINTERS structure as arguments. The arguments are the return values of calls to the Win32 API GetExceptionCode and GetExceptionInformation functions, respectively.

至于 _ set_se_translator 函数的具体机制,以及 把系统异常转化为 C++ 类型的异常的原理这里不再详细讨论,而仅仅是给出了大致的工作流程: 首先,通过 _ set_se_translator 函数设置一个对所有的 Windows 系统异常产生作用的回调处理函数(也是与 TLS 数据有关);因此,每当程序运行时产生了系统异常之后,前面我们设置的自定义回调函数于是便会接受程序的控制权;接着,我们在该函数的实现中,可以根据不 同类型的系统异常( EXCEPTION_POINTERS ),来分别抛出一个 C++ 类型的异常错误 。呵呵!简单吧!不再白话了,还是来瞧瞧阿愚所设计的一个简单演示例程吧!代码如下:

// FILENAME:SEH-test.cpp

#include <windows.h>

#include <cstdio>

#include <eh.h>

#include <string>

#include <exception>

using namespace std;

class seh_exception_base : public std::exception

{

public:

seh_exception_base (const PEXCEPTION_POINTERS pExp, std::string what )

: m_ExceptionRecord(*pExp->ExceptionRecord),

m_ContextRecord(*pExp->ContextRecord),

m_what(what){};

~seh_exception_base() throw(){} ;

virtual const char* what() const throw()

{

return m_what.c_str();

}

virtual DWORD exception_code() const throw()

{

return m_ExceptionRecord.ExceptionCode;

}

virtual const EXCEPTION_RECORD& get_exception_record() const throw()

{

return m_ExceptionRecord;

}

virtual const CONTEXT& get_context() const throw()

{

return m_ContextRecord;

}

// 初始化函数

static void initialize_seh_trans_to_ce()

{

_set_se_translator( trans_func );

}

// 系统异常出现时的回调函数

static void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp );

protected:

std::string m_what;

EXCEPTION_RECORD m_ExceptionRecord;

CONTEXT m_ContextRecord;

};

// 下面是系统异常被转换后的 C++ 类型的异常

// 篇幅有限,因此只简单设计了对几种常见的系统异常的转换

class seh_exception_access_violation : public seh_exception_base

{

public:

seh_exception_access_violation (const PEXCEPTION_POINTERS pExp, std::string what)

: seh_exception_base(pExp, what) {};

~seh_exception_access_violation() throw(){};

};

class seh_exception_divide_by_zero : public seh_exception_base

{

public:

seh_exception_divide_by_zero (const PEXCEPTION_POINTERS pExp, std::string what)

: seh_exception_base(pExp, what) {};

~seh_exception_divide_by_zero() throw(){};

};

class seh_exception_invalid_handle : public seh_exception_base

{

public:

seh_exception_invalid_handle (const PEXCEPTION_POINTERS pExp, std::string what)

: seh_exception_base(pExp, what) {};

~seh_exception_invalid_handle() throw(){};

};

// 系统异常出现时的回调函数

// 这里是实现,很关键。针对不同的异常,抛出一个 C++ 类型的异常

void seh_exception_base::trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )

{

switch(pExp->ExceptionRecord->ExceptionCode)

{

case EXCEPTION_ACCESS_VIOLATION :

throw seh_exception_access_violation(pExp, " 存储保护异常 ");

break;

case EXCEPTION_INT_DIVIDE_BY_ZERO :

throw seh_exception_divide_by_zero(pExp, " 被 0 除异常 ");

break;

case EXCEPTION_INVALID_HANDLE :

throw seh_exception_invalid_handle(pExp, " 无效句病异常 ");

break;

default :

throw seh_exception_base(pExp, " 其它 SEH 异常 ");

break;

}

}

// 来测试吧!

void main( void )

{

seh_exception_base::initialize_seh_trans_to_ce();

try

{

// 被 0 除

int x, y=0;

x = 5 / y;

// 存储保护

char* p =0;

*p = 0;

// 其它系统异常,例如中断异常

__asm int 3;

}

catch( seh_exception_access_violation& e )

{

printf( "Caught SEH_Exception. 错误原因: %s/n", e.what());

//other processing

}

catch( seh_exception_divide_by_zero& e )

{

printf( "Caught SEH_Exception. 错误原因: %s/n", e.what());

//other processing

}

catch( seh_exception_base& e )

{

printf( "Caught SEH_Exception. 错误原因: %s, 错误代码: %x/n", e.what(), e.exception_code());

}

}

总结

至此,关于 C++ 异常处理模型、 C 语言中的各种异常处理机制, Window 系统下的 SEH 原理,以及它们在使用上的各种技巧,和程序员在编程时使用这些异常处理机制时的注意事项等等,前面的相关文章中都做了较系统和深入的讨论和分析(也许错误 多多!欢迎指出和讨论)。相信不仅是主人公阿愚,而且包括那些细细地读过、品味过,和阿愚一块走过来的人,现在都有了一种豁然开朗的感觉。感谢各种异常处 理机制!感谢那些设计如此精妙技术和作品的天才!感谢天下所有有作为的程序员!

这篇关于如何把SEH类型的系统异常转化为C++类型的异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/501963

相关文章

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二