为 SIGFPE 设置标志并继续执行,忽略 FPE

问题描述 投票:0回答:1

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

我的尝试是启用我关心的 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
c linux floating-point signals
1个回答
7
投票

如果您只是想知道计算完成后是否发生浮点异常,那么您不应该使用信号,因为它们的开销很高。相反,请使用浮点异常标志,这些标志在正常执行期间由处理器快速设置。 (但是,访问它们可能会对性能产生一些影响。)

请参阅

<fenv.h>
上的 C 标准。简而言之:

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

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

© www.soinside.com 2019 - 2024. All rights reserved.