2

fenableexceptが欠落しているMinGW GCCで浮動小数点例外を有効にするにはどうすればよいですか? かなり完全なソリューションでさえ、意図しているように見えますが、実際にはこれをキャッチしません。私は、将来の標準に近い最小限のコードを好みます。できれば、コードは SSE の有無にかかわらず機能する必要があります。ハードウェア信号を有効にし、キャッチし、リセットする方法を示す完全なソリューションが望ましいです。高い最適化レベルと完全なペダンティック エラーと警告でクリーンにコンパイルすることは必須です。単体テストのシナリオで複数回キャッチできることは重要です。部分的な回答を提供する質問がいくつかあります。

4

1 に答える 1

1

これは私のマシンで動作するようです。を使用して MinGW GCC でコンパイルし-fnon-call-exceptionsます。まだ完全に最小化されていません。

#include <xmmintrin.h>
#include <cerrno>
#include <cfenv>
#include <cfloat> //or #include <float.h> // defines _controlfp_s
#include <cmath>
#include <csignal>

#ifdef _WIN32
void feenableexcept(uint16_t fpflags){
 /*edit 2015-12-17, my attempt at ASM code was giving me
  *problems in more complicated scenarios, so I
  *switched to using _controlfp_s. I finally posted it here
  *because of the upvote to the ASM version.*/
 /*{// http://stackoverflow.com/questions/247053/
  uint16_t mask(FE_ALL_EXCEPT & ~fpflags);
  asm("fldcw %0" : : "m" (mask) : "cc");
 } //https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html   */
 unsigned int new_word(0);
 if (fpflags & FE_INVALID) new_word |= _EM_INVALID;
 if (fpflags & FE_DIVBYZERO) new_word |= _EM_ZERODIVIDE;
 if (fpflags & FE_OVERFLOW) new_word |= _EM_OVERFLOW;
 unsigned int cw(0);
 _controlfp_s(&cw,~new_word,_MCW_EM);
}
#endif

void fe_reset_traps(){
 std::feclearexcept(FE_ALL_EXCEPT); //clear x87 FE state
#ifdef __SSE__
 _MM_SET_EXCEPTION_STATE(0); // clear SSE FE state
#endif
 feenableexcept(FE_DIVBYZERO|FE_OVERFLOW|FE_INVALID); // set x87 FE mask
#ifdef __SSE__
 //set SSE FE mask (orientation of this command is different than the above)
 _MM_SET_EXCEPTION_MASK(_MM_MASK_DENORM |_MM_MASK_UNDERFLOW|_MM_MASK_INEXACT);
#endif
}

void sigfpe_handler(int sig){
 std::signal(sig,SIG_DFL); // block signal, if needed
 std::cerr<<"A floating point exception was encountered. Exiting.\n";
 fe_reset_traps(); // in testing mode the throw may not exit, so reset traps
 std::signal(sig,&sigfpe_handler); // reinstall handler
 throw std::exception();
}

fe_reset_traps();
std::signal(SIGFPE,&sigfpe_handler); // install handler
std::cerr<<"before\n";
std::cerr<<1.0/0.0<<"\n";
std::cerr<<"should be unreachable\n";

完璧ではないことは確かです。他の誰もが貢献しなければならないことを聞いてみましょう。

于 2015-05-11T18:57:54.607 に答える