例
int *ptr;
*ptr = 1000;
我可以使用标准C ++而不使用任何特定于Microsoft的方法来捕获内存访问冲突异常。
例
int *ptr;
*ptr = 1000;
我可以使用标准C ++而不使用任何特定于Microsoft的方法来捕获内存访问冲突异常。
Answers:
不。当您做不好的事情时,C ++不会引发异常,这会导致性能下降。诸如访问冲突或除以零错误之类的事情更像是“机器”异常,而不是您可以捕获的语言级别的事情。
阅读并哭泣!
我想到了。如果您不从处理程序中抛出,则处理程序将继续运行,异常也将继续。
当您抛出自己的异常并处理该异常时,魔术就会发生。
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Signal %d",signal);
throw "!Access Violation!";
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGSEGV , SignalHandler);
try{
*(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
}
catch(char *e)
{
printf("Exception Caught: %s\n",e);
}
printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
printf("But please kids, DONT TRY THIS AT HOME ;)\n");
}
sigaltstack
使它能够在POSIX上运行,必须没有安装任何替代的信号堆栈()(除非C ++异常展开实现允许),并且处理展开机制本身的每个运行时函数都应该是信号安全的。
signal(SIGSEGV, SIG_DFL);
使用try-> catch(...)块,在Visual Studio中有一种非常简单的方法来捕获任何类型的异常(零除,访问冲突等)。较小的项目设置调整就足够了。只需在项目设置中启用/ EHa选项。请参见项目属性-> C / C ++->代码生成->将启用C ++异常修改为“是,并带有SEH异常”。而已!
在此处查看详细信息:http : //msdn.microsoft.com/zh-cn/library/1deeycx5(v=vs.80).aspx
至少对我来说,signal(SIGSEGV ...)
另一个答案中提到的方法不适用于带有Visual C ++ 2015的Win32。什么做的工作对我来说是使用_set_se_translator()
中发现的eh.h
。它是这样的:
步骤1)确保在“项目属性” /“ C ++” /“代码生成” /“启用C ++异常”中启用带有SEH异常(/ EHa)的“是”,如Volodymyr Frytskyy的回答中所述。
步骤2)调用_set_se_translator()
,传入新异常转换器的函数指针(或lambda)。之所以称为翻译器,是因为它基本上只接受低级别的异常并将其重新引发为更容易捕获的东西,例如std::exception
:
#include <string>
#include <eh.h>
// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
std::string error = "SE Exception: ";
switch (u) {
case 0xC0000005:
error += "Access Violation";
break;
default:
char result[11];
sprintf_s(result, 11, "0x%08X", u);
error += result;
};
throw std::exception(error.c_str());
});
步骤3)像平常一样捕获异常:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
这种情况取决于实现,因此将需要特定于供应商的机制才能进行捕获。对于Microsoft,这将涉及SEH,而* nix将涉及一个信号
通常,尽管捕获访问冲突异常是一个非常糟糕的主意。几乎没有办法从AV异常中恢复,尝试这样做将导致程序中更难发现错误。
如前所述,在Windows平台上没有非Microsoft /编译器供应商的方式来执行此操作。但是,显然可以通过常规try {} catch(exception ex){}方式捕获这些类型的异常,以进行错误报告,并更正常地退出应用(如JaredPar所说,该应用现在可能有麻烦了) 。我们在一个简单的类包装器中使用_se_translator_function,它使我们可以在try处理程序中捕获以下异常:
DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)
原始类来自这篇非常有用的文章:
不是异常处理机制,但是您可以使用C提供的signal()机制。
> man signal
11 SIGSEGV create core image segmentation violation
写入NULL指针可能会导致SIGSEGV信号
signal()
是posix标准的一部分。Windows实现posix标准(Linux和unix也是如此)
那样的违规意味着代码中有严重的错误,并且是不可靠的。我可以看到程序可能希望以一种希望不会覆盖以前的数据的方式来尝试保存用户的数据,以希望用户的数据尚未损坏,但是根据定义,没有标准方法处理未定义的行为。