Visual c++ visualc&x2B+;/启用浮点异常后的奇怪行为(编译器错误?)

Visual c++ visualc&x2B+;/启用浮点异常后的奇怪行为(编译器错误?),visual-c++,exception,floating-point,divide-by-zero,Visual C++,Exception,Floating Point,Divide By Zero,在VisualStudio(2005或2008)下,我正在努力找到一种可靠的方法来捕获浮点异常。默认情况下,在VisualStudio下,浮点异常不会被捕获,并且很难捕获(主要是因为它们大多数是硬件信号,需要转换为异常) 以下是我所做的: -启用SEH异常处理 (属性/代码生成/启用C++异常:是的,有SEH例外) -使用_controlfp激活浮点异常 我现在确实捕获了异常(如下面的示例所示,其中有一个简单的除以零异常)。 然而,当我发现这个异常时,程序似乎已损坏到无法修复的程度(因为简单的浮

在VisualStudio(2005或2008)下,我正在努力找到一种可靠的方法来捕获浮点异常。默认情况下,在VisualStudio下,浮点异常不会被捕获,并且很难捕获(主要是因为它们大多数是硬件信号,需要转换为异常)

以下是我所做的:
-启用SEH异常处理
(属性/代码生成/启用C++异常:是的,有SEH例外) -使用_controlfp激活浮点异常

我现在确实捕获了异常(如下面的示例所示,其中有一个简单的除以零异常)。 然而,当我发现这个异常时,程序似乎已损坏到无法修复的程度(因为简单的浮点初始化以及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();
}
#包括“stdafx.h”
#包括
#包括
#包括
使用名称空间std;
//碳纤维http://www.fortran-2000.com/ArnaudRecipes/CompilerTricks.html#x86_FP
//cf还出版了《数字食谱》一书,书中给出了同样的建议
//关于如何激活fp异常
void TurnOnFloatingExceptions()
{
无符号整数连续波;
//注:与controlfp的结果相同
cw=_control87(0,0)&MCW_EM;
cw&=~(_EM_无效| u EM_零除| u EM_溢出);
_控制87(cw,MCW_EM);
}
//简单检查以确保浮点数学仍然有效
作废支票浮动()
{
尝试
{
//这个简单的初始化可能会中断
//在浮点异常之后!
双k=3。;

当捕获浮点异常时,必须清除状态字中的FPU异常标志。调用_clearfp()


考虑使用_set_se_translator()编写一个异常过滤器,将硬件异常转化为C++异常。请务必选择,只翻译FPU异常。

< P>附加信息:如果您在64位Windows上运行32位代码,使用/ARCH:SSE2或其他选项,启用SSE2指令集,或其超集之一,则可能需要做一个更剧烈的重置


对于Visual Studio 2015(可能还有更高版本),您需要在SSE2寄存器中生成的浮点陷阱之后调用_fpreset(),而不仅仅是_clearfp()。如果您使用Visual Studio 2013及更早版本执行此操作,您会遇到各种奇怪的问题,这是由于运行时库变得混乱造成的。

但有一个重要注意事项:_fpreset()将清除浮点状态字并重新初始化浮点数学包,即随后将不会引发异常。为了不禁用后续异常,可以使用_clearfp()代替标题,因为标题与OQ有相同的问题(所以对你们两个来说都是大+1)。