2010-11-26 27 views
8

Visual Studio(2005または2008)で浮動小数点例外を確実に捕捉するのに苦労しています。デフォルトでは、ビジュアルスタジオの下では、浮動小数点例外は捕捉されず、(ハードウェア信号のほとんどが例外であり、例外に変換される必要があるため)捕捉するのが非常に難しいです。浮動小数点例外を有効にした後のVisual C++ /奇妙な振る舞い(コンパイラのバグ?)

ここで私は何をしましたか:
は -
取り扱い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(); 
} 

誰でもこの状況を修正するための手がかりを持っていますか? 事前に感謝します!

答えて

10

浮動小数点例外をキャッチするときは、ステータスワード内のFPU例外フラグをクリアする必要があります。 _clearfp()を呼び出します。

_set_se_translator()を使用して、ハードウェア例外をC++例外に変換する例外フィルタを記述することを検討してください。選択的で、FPUの例外のみを翻訳するようにしてください。

+2

ただし、_fpreset()は浮動小数点ステータスワード*をクリアし、浮動小数点数学パッケージを再初期化します。つまり、後で例外はスローされません。その後の例外を無効にしないために、代わりに_clearfp()を使用することができます –

+0

私はOQと同じ問題を抱えていました。 –

1

追加情報:64ビットウィンドウで32ビットコードを実行していて、/ arch:SSE2またはSSE2命令セットまたはそのスーパーセットの1つを有効にするその他のオプションを使用する場合は、劇的なリセット。

Visual Studio 2015(およびそれ以降のバージョン)では、_clearfp()だけでなく、SSE2レジスタで生成された浮動小数点トラップの後に_fpreset()を呼び出す必要があります。 Visual Studio 2013以前でこれを行うと、ランタイムライブラリが混乱するためにさまざまな奇妙な問題が発生します。