【问题标题】:Set flag for SIGFPE and continue execution ignoring FPEs为 SIGFPE 设置标志并继续执行忽略 FPE
【发布时间】:2013-07-10 21:10:38
【问题描述】:

在数值应用中,我想知道计算完成后是否发生浮点异常。默认情况下,浮点除法和无效操作会被静默忽略。

我的尝试是启用我关心的 FPE,通过设置一个标志来处理 SIGFPE,然后再次禁用它们以允许继续执行:

#include <fenv.h>
#include <signal.h>
#include <stdio.h>

int caught = 0;
struct sigaction old_sa;
/* (2) */ fenv_t fenv_hold;

void sighandler()
{
    caught = 1;
    printf("Caught in handler, disabling\n");
    /* (1) */ fedisableexcept(FE_ALL_EXCEPT);
    /* (2) */ feholdexcept(&fenv_hold);
    sigaction(SIGFPE, &old_sa, NULL);
}

int main(void)
{
    struct sigaction sa;
    volatile double a=1, b=0;

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO; 
    sa.sa_sigaction = sighandler;
    sigaction(SIGFPE, &sa, &old_sa);

    feenableexcept(FE_DIVBYZERO);
    printf("Dividing by zero..\n");
    a/=b;
    printf("Continuing\n");
}

我采用了两种方法,第一种方法用(1) 标记,第二种方法用(2) 标记。它们都没有按预期工作。

输出:

Dividing by zero..
Caught in handler, disabling
Floating point exception (core dumped)

预期输出:

Dividing by zero..
Caught in handler, disabling
Continuing

【问题讨论】:

  • 1) void sighandler() 应该是 void sighandler(int signum) 2) 你不应该从信号处理程序中调用 printf。
  • 感谢您的评论,我知道了。此代码仅用于演示。

标签: c linux floating-point signals


【解决方案1】:

如果您只想知道在计算完成后是否发生浮点异常,那么您不应该使用信号,因为它们的开销很大。相反,请使用浮点异常标志,它们在正常执行期间由处理器快速设置。

请参阅&lt;fenv.h&gt; 上的 C 标准。简要说明:

  • 在您的源文件中插入#include &lt;fenv.h&gt;
  • 在任何可能访问浮点标志或在非默认浮点模式下运行的源代码之前插入 #pragma STDC FENV_ACCESS on
  • 如果需要,当以下源代码无法访问标志或在非默认模式下运行时,在上述源代码之后插入#pragma STDC FENV_ACCESS off
  • 在计算之前,执行feclearexcept(FE_ALL_EXCEPT) 以清除标志。
  • 计算后,执行fetestexcept(exceptions) 测试标志。 exceptions 应该是 FE_DIVBYZEROFE_INEXACTFE_INVALIDFE_OVERFLOW 和/或 FE_UNDERFLOW 的按位或,可能还有其他实现定义的标志。

请注意,某些 C 实现对访问浮点环境的支持较差。

【讨论】:

  • 如果实现支持不佳,使用信号处理程序不会更好。支持的问题是编译器可能会进行无效优化,导致发生与抽象机器上不同的异常。
猜你喜欢
  • 2019-04-10
  • 2013-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-26
  • 2011-12-01
  • 2013-03-13
  • 1970-01-01
相关资源
最近更新 更多