2011-01-14 7 views
0

私はdoubleをfloatに変換しようとしていますし、dll内のさまざまな整数型をGame Maker拡張機能として使用しています。ダブルがターゲットタイプの範囲に収まらない場合、私は賢明な結果を必要としないので、単にstatic_castを使用しました。C++でSIGFPEを防止/抑制するにはどうすればよいですか?

私のテストC++アプリケーションからこのコードを呼び出すと、すべてが意図した通りに動作しますが、Game Makerから呼び出されると、何らかの理由でエラーが発生し、SIGFPEが発生し、Game Makerはプログラムをエラーメッセージで終了させます。

範囲外のコンバージョンではわかりやすい結果は必要ありませんが、クラッシュはノー・ノーです。私はキャストの代わりにllroundを使用しようとしましたが、シグナルも上がります。

私はsignal(SIGFPE、SIG_IGN)を使って自分自身で信号を捕まえることも試みました。変換の直前に、それはまったく動作を変更しませんでした。おそらく、mingw signal.hの不吉なコメントには、「SIGFPEは動作していないのですか?

Game Maker拡張機能で使用されている別のdllのソースコードを確認しました。作成者が提供するバイナリは問題なく単純なキャスト変換を実行します。しかし、ソースを自分自身でコンパイルすると、SIGFPEの問題が再び発生します。私は作者が別のコンパイラを使用していたと推測していますが、可能であればmingwと一緒にいたいと思います。

これらの変換を安全に実行するか、単純なキャストで信号を実行すると信号が生成されないようにするにはどうすればよいですか?私は現在mingw-g ++ 4.5.0を使用してコンパイルしています。

ここで問題が発生した機能です:

template<typename ValueType> 
static double writeIntValue(double handle, double value) { 
    boost::shared_ptr<Writable> writable = handles.find<Writable>(handle); 
    if(writable) { 
     // Execution reaches this point 
     ValueType converted = static_cast<ValueType>(value); 
     // Execution doesn't reach this point if e.g. ValueType 
     // is short and value is 40000 
     writable->write(reinterpret_cast<uint8_t *>(&converted), sizeof(converted)); 
    } 
    return 0; 
} 
+0

SIGFPEを引き起こす範囲外の変換であり、0で除算されていないことは確かですか? –

+0

はい。私は、問題が発生した関数のコードを追加し、除算も0も存在しません。 – Medo42

答えて

1

良い解決策は、ソース値がキャスト前に、ターゲット・タイプの範囲内であることを確実にすることによって正しく変換を行うことです。そこで質問から、私のコードは次のように修正することができます。

ValueType converted; 
if(value >= std::numeric_limits<ValueType>::max()) { 
    converted = std::numeric_limits<ValueType>::max(); 
} else if(value <= std::numeric_limits<ValueType>::min()) { 
    converted = std::numeric_limits<ValueType>::min(); 
} else { 
    converted = static_cast<ValueType>(value); 
} 

別のオプションは、ソース値が範囲外の場合、例外をスローした、Boostライブラリからnumeric_castを使用することですので、それはすべての動作を定義していますコンバージョン

ブースト数値変換ライブラリのドキュメントには、標準で特定のコンバージョンがどのように定義されたかに関するhelpful informationが含まれています。

彼の答えで正しい提案を提供してくれたrveのおかげで、残念なことに彼のサンプルコードに欠陥がありました。私は助けてくれる追加のポインタを追加したかったのです。

0

おそらくそれは、変換自体ではなく(多分破損またはそのような何かをスタック)無効なメモリにアクセスしようと関係ないですが。いくつかのコードスニペットを提供できますか?

+0

コードが追加されました。私はデバッガでこの場所でSIGFPEが生成されていることを発見しました。もし無効なメモリに接続されていた場合、値が範囲外になったときに問題は起こりません。 – Medo42

1

DLLを使用しているので、DLLはプログラムが期待するのと同じ方法でコンパイルされていますか?たぶん32/64ビットのミスマッチがありますか?

また、変換時にアンダーフローまたはオーバーフローが発生すると、SIGFPEを立ち上げることもできます。

_FPU_SETCW(それはfpu_control.hにあります)を使用してマスクを設定することで、このオーバフローによって発生した信号を有効/無効にできます。私の推測では、これとテストプログラムは使用できません。

私はこれを試したことはありませんし、mingwもこれを持っているか分かりませんが、少し助けてくれることを願っています。

編集:

はなぜオーバーフローが起こらないことを確認することではありませんか?以下のような

何か:

if (value > std::numeric_limits<ValueType>::max()) 
{ 
    value = std::numeric_limits<ValueType>::max(); 
} 
else if (value < std::numeric_limits<ValueType>::min()) 
{ 
    value = std::numeric_limits<ValueType>::min(); 
} 
ValueType converted = value; 
+0

あなたの答えをありがとう。 fpu_control.hは利用できないので、私はこれをテストすることができませんでしたが、このような目標範囲に値をクランプすることで私の問題は解決します。私はこれを解決策としてマークしたいが、小さな問題が残っている。int64_tへの変換は失敗する可能性がある。なぜなら、その最大値を二重に格納することは不正確になり、int64_t範囲外の値を再び与えるからである。 これは当然のことながら解決するのは簡単ですが、私はこれを検索する次の人のために答えてください – Medo42

関連する問題