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

Set flag for SIGFPE and continue execution ignoring FPEs

提问人:Fabian Knorr 提问时间:7/11/2013 更新时间:11/17/2023 访问量:1345

问:

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

我的尝试是启用我关心的 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 浮点 信号

评论

0赞 Pascal Cuoq 7/11/2013
处理浮点异常的可能重复项
2赞 wildplasser 7/11/2013
1) 应该是 2) 不应从信号处理程序中调用 printf。void sighandler()void sighandler(int signum)
0赞 Fabian Knorr 7/11/2013
谢谢你的评论,我知道。此代码仅用于演示。

答:

7赞 Eric Postpischil 7/11/2013 #1

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

请参阅 上的 C 标准。简要:<fenv.h>

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

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

评论

1赞 R.. GitHub STOP HELPING ICE 7/11/2013
如果实现的支持较差,则使用信号处理程序不会更好。支持的问题在于,编译器可能会进行无效的优化,从而导致发生与抽象计算机上应该发生的异常不同的异常。