如何在C ++中阻止/抑制SIGFPE?

时间:2011-01-14 11:27:51

标签: c++

我正在尝试将double转换为float以及dll中的各种整数类型,它用作Game Maker扩展。如果double不符合目标类型的范围,我不需要合理的结果,所以我只使用了static_cast。

当我从我自己的测试C ++应用程序调用此代码时,一切都按预期工作,但是当它从Game Maker调用时,范围错误由于某种原因引发SIGFPE,这导致Game Maker通过错误消息终止我的程序。

对于超出范围的转换,我不需要明智的结果,但崩溃是禁忌。我尝试使用llround而不是强制转换,但它也会提升信号。

我也试过用信号(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;
}

3 个答案:

答案 0 :(得分:1)

由于您使用的是DLL,您确定DLL的编译方式与程序所期望的相同吗?也许有些32/64位不匹配?

此外,转换时出现欠/溢时也可以引发SIGFPE。

您可以通过使用_FPU_SETCW设置掩码来启用/禁用此溢出引发的信号(它位于fpu_control.h)我的猜测是Game Maker启用此功能而您的测试程序不支持。

我从来没有尝试过这个,我也不确定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;

答案 1 :(得分: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,如果源值超出范围,则抛出异常,因此它已为所有转换定义了行为。

Boost数字转换库的文档包含一些关于标准如何定义某些转换的helpful information

感谢rve在他的回答中提供了正确的建议,但不幸的是他的示例代码存在缺陷,我想添加一些帮助我的其他指针。

答案 2 :(得分:0)

可能它与转换本身无关,但试图访问无效内存(可能是堆栈损坏或类似的东西)。你能提供一些代码片段吗?