简体   繁体   English

如何在C ++中预防/抑制SIGFPE?

[英]How do I prevent/suppress SIGFPE in C++?

I'm trying to convert a double to float as well as various integer types inside a dll, which is used as a Game Maker extension. 我正在尝试将double转换为float以及dll中的各种整数类型,该dll被用作Game Maker扩展程序。 I don't need a sensible result if the double doesn't fit the range of the target types, so I simply used a static_cast. 如果双精度数不适合目标类型的范围,则不需要明智的结果,因此我只使用了static_cast。

Everything works as intended when I call this code from my own test C++ application, but when it's called from Game Maker, range errors raise SIGFPE for some reason, which leads Game Maker to terminate my program with an error message. 当我从自己的测试C ++应用程序中调用此代码时,一切都按预期方式工作,但是当从Game Maker调用该代码时,由于某些原因,范围错误会引发SIGFPE,这会导致Game Maker终止并显示错误消息。

I don't need sensible results for out-of-range conversions, but crashing is a no-no. 对于超出范围的转换,我不需要明智的结果,但是崩溃是不行的。 I tried using llround instead of a cast, but it also raises the signal. 我尝试使用llround而不是强制转换,但它也会引发信号。

I also tried catching the signal myself by using signal(SIGFPE, SIG_IGN); 我还尝试通过使用signal(SIGFPE,SIG_IGN)来捕获信号。 right before the conversion, but it didn't change the behaviour at all. 就在转换之前,但它根本没有改变行为。 Maybe the ominous comment in the mingw signal.h has something to do with that: "SIGFPE doesn't seem to work?" 也许在mingw signal.h中不祥的评论与此有关:“ SIGFPE似乎不起作用?”

I checked the source code of a different dll used in a Game Maker extension, and the binary provided by the author performs simple cast conversions without a problem. 我检查了Game Maker扩展中使用的其他dll的源代码,作者提供的二进制文件执行了简单的转换,没有问题。 When I compile the source myself however, the SIGFPE problem is present again. 但是,当我自己编译源代码时,再次出现了SIGFPE问题。 I am guessing that the author used a different compiler, but I'd prefer to stay with mingw if possible. 我猜想作者使用了不同的编译器,但如果可能的话,我宁愿留在mingw。

So, how do I either perform these conversions safely, or prevent the signal from being generated when I perform them with a simple cast? 因此,如何安全地执行这些转换,或者在通过简单的转换执行它们时如何防止产生信号? I'm using mingw-g++ 4.5.0 to compile at the moment. 我目前正在使用mingw-g ++ 4.5.0进行编译。

Here's the function where the problem happens: 这是发生问题的函数:

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;
}

Since you are using a DLL, are you sure the DLL is compiled in the same way as the program expects it? 由于您使用的是DLL,您确定DLL的编译方式与程序预期的相同吗? Maybe some 32/64 bit mismatch? 也许一些32/64位不匹配?

Also, SIGFPE can also be raised when there is an under/overflow when converting. 同样,当转换时出现下溢/上溢时,SIGFPE也可以提高。

You can enable/disable the signal raised by this overflow by setting the mask using _FPU_SETCW (it's in fpu_control.h ) My guess is that Game Maker enables this and your test program not. 您可以通过使用_FPU_SETCW (位于fpu_control.h )设置掩码来启用/禁用由此溢出引起的信号(我猜是Game Maker启用了此功能,而您的测试程序未启用)。

I never tried this and I'm not sure mingw also has this but I hope this helps a little. 我从来没有尝试过,我不确定mingw也有这个,但是我希望这会有所帮助。

edit: 编辑:

Why not making sure an overflow does not happen? 为什么不确保不会发生溢出?

Something like: 就像是:

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;

The good solution is to perform the conversion correctly by ensuring that the source value is within the range of the target type before casting. 好的解决方案是通过在转换之前确保源值在目标类型的范围内来正确执行转换。 So my code from the question could be corrected like this: 所以我的问题代码可以像这样纠正:

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

Another option is to use numeric_cast from the Boost libraries, which throws an exception if the source value is out of range, so it has defined behaviour for all conversions. 另一个选择是使用Boost库中的numeric_cast,如果源值超出范围,则会引发异常,因此它为所有转换定义了行为。

The documentation of the Boost Numeric Conversion library contains some helpful information about how the standard defined certain conversions. Boost Numeric Conversion库的文档包含一些有关标准如何定义某些转换的有用信息

Thanks to rve for providing the correct suggestion in his answer, but unfortunately his example code is flawed, and I wanted to add some additional pointers that helped me. 感谢rve在他的回答中提供了正确的建议,但是不幸的是他的示例代码有缺陷,我想添加一些对我有帮助的指针。

probably it's not related with conversion itself but with trying to access invalid memory (maybe stack corruptions or something like that). 可能与转换本身无关,但与尝试访问无效的内存(可能是堆栈损坏或类似问题)有关。 can you provide some code snippet? 您可以提供一些代码片段吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM