2010-11-26 39 views
8

estoy luchando para conseguir una manera fiable para atrapar flotante señala excepciones bajo Visual Studio (2005 o 2008). De forma predeterminada, en visual studio, las excepciones de punto flotante no son capturadas, y son bastante difíciles de detectar (principalmente porque la mayoría de ellas son señales de hardware y deben traducirse en excepciones)Visual C++/comportamiento extraño después de habilitar las excepciones de punto flotante (error del compilador?)

Esto es lo que hice:
- Activar el manejo
excepciones SEH (/ Habilitar excepciones de generación de propiedades/código C++: Sí, con excepciones SEH)
- Activar flotante señala excepciones usando _controlfp

hago ahora detectar las excepciones (como se muestra en el ejemplo siguiente que una simple división por cero excepción). Sin embargo, tan pronto como veo esta excepción, parece que el programa está irremediablemente dañado (¡ya que la inicialización simple del flotador, así como std :: cout no funcionarán!).

he construido un programa de demostración simple que muestra este comportamiento más bien raro.

Nota: este comportamiento se reprodujo en varios ordenadores.

#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(); 
} 

¿Alguien tiene alguna pista sobre qué se puede hacer para corregir esta situación? ¡Muchas gracias de antemano!

Respuesta

10

se deben eliminar las banderas de excepción FPU en la palabra de estado cuando se captura una excepción de punto flotante. Llamar a _clearfp().

considerar el uso de _set_se_translator() para escribir un filtro de excepción que traducen la excepción de hardware a una excepción de C++. Asegúrese de ser selectivo, solo traduzca las excepciones de FPU.

+2

Una nota importante, sin embargo: _fpreset() borrará la palabra de estado de coma flotante * y * reinicializa el paquete de matemáticas de punto flotante, es decir excepciones no serán lanzados posteriormente. Para no deshabilitar excepciones posteriores, _clearfp() se puede usar en su lugar –

+0

Tuve el mismo problema que el OQ (por lo que un gran +1 para ambos). –

1

Información adicional: si está ejecutando código de 32 bits en Windows de 64 bits y usa/arch: SSE2 u otras opciones que habilitan el conjunto de instrucciones SSE2, o uno de sus superconjuntos, es posible que deba hacer un restauración drástica

Con Visual Studio 2015 (y, presumiblemente, versiones posteriores), debe llamar a _fpreset() después de trampas de punto flotante generadas en los registros SSE2, en lugar de simplemente _clearfp(). Si hace esto con Visual Studio 2013 y anteriores, obtendrá una variedad de problemas extraños, causados ​​por la biblioteca en tiempo de ejecución que se confunde.

Cuestiones relacionadas