我正在努力获得一种可靠的方法来捕获Visual Studio(2005或2008)下的浮点异常。默认情况下,在visual studio下,浮点异常没有被捕获,并且它们很难捕获(主要是因为它们中的大多数是硬件信号,需要转换为异常)
这是我做的:
- 打开SEH异常处理
(属性/代码生成/启用C ++异常:是的,具有SEH异常)
- 使用_controlfp
我现在抓住异常(如下面的例子中所示,简单的除以零除外)。 但是,一旦我捕获到这个异常,似乎程序被无可挽回地破坏了(因为简单的float初始化,以及std :: cout将不起作用!)。
我已经构建了一个简单的演示程序,显示了这种相当奇怪的行为。
注意:此行为已在多台计算机上重现。
#include "stdafx.h"
#include <math.h>
#include <float.h>
#include <iostream>
using namespace std;
//cf http://www.fortran-2000.com/ArnaudRecipes/CompilerTricks.html#x86_FP
//cf also the "Numerical Recipes" book, which gives the same advice
//on how to activate fp exceptions
void TurnOnFloatingExceptions()
{
unsigned int cw;
// Note : same result with controlfp
cw = _control87(0,0) & MCW_EM;
cw &= ~(_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW);
_control87(cw,MCW_EM);
}
//Simple check to ensure that floating points math are still working
void CheckFloats()
{
try
{
// this simple initialization might break
//after a float exception!
double k = 3.;
std::cout << "CheckFloatingPointStatus ok : k=" << k << std::endl;
}
catch (...)
{
std::cout << " CheckFloatingPointStatus ==> not OK !" << std::endl;
}
}
void TestFloatDivideByZero()
{
CheckFloats();
try
{
double a = 5.;
double b = 0.;
double c = a / b; //float divide by zero
std::cout << "c=" << c << std::endl;
}
// this catch will only by active:
// - if TurnOnFloatingExceptions() is activated
// and
// - if /EHa options is activated
// (<=> properties / code generation / Enable C++ Exceptions : Yes with SEH Exceptions)
catch(...)
{
// Case 1 : if you enable floating points exceptions ((/fp:except)
// (properties / code generation / Enable floting point exceptions)
// the following line will not be displayed to the console!
std::cout <<"Caught unqualified division by zero" << std::endl;
}
//Case 2 : if you do not enable floating points exceptions!
//the following test will fail!
CheckFloats();
}
int _tmain(int argc, _TCHAR* argv[])
{
TurnOnFloatingExceptions();
TestFloatDivideByZero();
std::cout << "Press enter to continue";//Beware, this line will not show to the console if you enable floating points exceptions!
getchar();
}
有没有人知道如何纠正这种情况? 非常感谢提前!
答案 0 :(得分:10)
捕获浮点异常时,必须清除状态字中的FPU异常标志。调用_clearfp()。
考虑使用_set_se_translator()编写一个异常过滤器,将硬件异常转换为C ++异常。一定要有选择性,只能翻译FPU例外。
答案 1 :(得分:1)
附加信息:如果您在64位窗口上运行32位代码,并使用/ arch:SSE2或其他启用SSE2指令集或其中一个超集的选项,则可能需要更加激烈重启。
使用Visual Studio 2015(可能是更高版本),您需要在SSE2寄存器中生成的浮点陷阱之后调用_fpreset(),而不仅仅是_clearfp()。如果使用Visual Studio 2013及更早版本执行此操作,则会出现由运行时库混淆导致的各种奇怪问题。