我使用以下MSVC ++控制台应用程序代码(在Windows 8.1,Release,Win32上运行)尝试将顶级异常返回给我:
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS exception)
{
printf("Got an unhandled exception.");
return EXCEPTION_CONTINUE_SEARCH;
}
int _tmain(int argc, _TCHAR* argv[])
{
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
int a = 0;
int b = 0;
int c = a / b;
cin.get();
return 0;
}
我的UnhandledExceptionFilter
实际上似乎没有被调用此示例中抛出的除零异常,否则我会期望&#34;得到未处理的异常&#34;显示日志消息。那是为什么?
答案 0 :(得分:7)
整数除零是未定义的行为。如果实现选择为此引发异常(或任何其他未定义的行为),那很好。如果某个实现选择不来为某些未定义的行为引发异常,那也没关系。无论面对未定义的行为时实现的是什么都没关系。这不是他们的问题。
显然在Windows 8.1上运行MSVC ++,Win32不会在除以零时引发异常。
你永远不应该期望未定义的行为会产生预期的结果。
答案 1 :(得分:3)
如果应用程序在调试器下运行,则不会调用SetUnhandledExceptionFilter()指定的函数,这个想法是SetUnhandledExceptionFilter()只应该用于生成崩溃转储然后退出应用程序。如果您连接了调试器,这不是很有用,因此调试器将首先处理异常。
MSDN documentation引用了这个:
调用此函数后,如果进程中发生异常 没有被调试,异常使它成为未处理的 异常过滤器,该过滤器将调用异常过滤器函数 由lpTopLevelExceptionFilter参数指定。
答案 2 :(得分:0)
除以零实际上是一个CPU陷阱,不仅仅是编程意义上的异常。您应该定义陷阱处理程序而不是异常处理程序。
答案 3 :(得分:0)
在我看来,从操作系统的角度看,异常实际上并不是真正的未处理异常。您正在呼叫printf
,因此您已在CRT中进行了关联。 IIRC,CRT处理从main
转义的异常,但是从操作系统的角度来看,未处理的异常是逃避真正入口点的异常 - 即调用main的CRT函数。
我相信你真的想要一个矢量异常处理程序。
答案 4 :(得分:0)
1)如@zhenguoli所说,UnhandledExceptionFilter
是在kernel32.lib中定义的,因此它不会链接。您需要将异常过滤器命名为其他名称。 UnhandledExceptionFilter
就是由SetUnhandledExceptionFilter
设置的异常处理程序。
2)@DavidHammen尚不清楚,因为在x86上确实使用异常向量0处理了div被零除,并且GetExceptionCode()
将返回EXCEPTION_INT_DIVIDE_BY_ZERO
。但是,正如@davidbak所说,在OP的示例中,编译器不允许这样做,因为未使用变量c并将其优化。如果使用c,则向量0处的异常处理程序将开始展开堆栈并最终调用UnhandledExceptionFilter
作为过滤器表达式,该表达式包装在BaseProcessStartup
中的线程入口函数周围,然后将调用您的处理程序(线程以BaseProcessStartup
作为入口函数开始,并以实际线程入口函数作为参数)。 .exe进入功能将初始化CRT,然后调用main。请注意,divbyzero无法更早地捕获,因为看来c ++异常对象从未编译为EXCEPTION_INT_DIVIDE_BY_ZERO
–请参见https://stackoverflow.com/a/6121690/7194773。