【问题标题】:Can I ignore a SIGFPE resulting from division by zero?我可以忽略除以零导致的 SIGFPE 吗?
【发布时间】:2010-09-29 23:46:36
【问题描述】:

我有一个程序故意执行除以零(并将结果存储在 volatile 变量中)以便在某些情况下停止。但是,我希望能够禁用这种暂停,而无需更改执行除以零的宏。

有什么办法可以忽略吗?

我试过了

#include <signal.h>
...
int main(void) {
  signal(SIGFPE, SIG_IGN);
  ...
}

但它仍然会因消息“浮点异常(核心转储)”而死亡。

我实际上并没有使用该值,所以我并不真正关心分配给变量的内容; 0、随机、未定义...

编辑:我知道这不是最便携的,但它适用于在许多不同操作系统上运行的嵌入式设备。默认停止动作是除以零;其他平台需要不同的技巧来强制看门狗引起的重启(例如禁用中断的无限循环)。对于 PC (linux) 测试环境,我想禁用除以零时的暂停,而不依赖于断言之类的东西。

【问题讨论】:

标签: signals posix divide-by-zero sigfpe


【解决方案1】:
void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);

【讨论】:

    【解决方案2】:

    lnmiit l 在崩溃的代码上,然后我还建议更改代码以其他方式死掉。如果你不这样做,你可以尝试安装一个

    【讨论】:

    • 您可能想要完成并澄清您的答案。在目前的状态下,部分似乎丢失了,至少还不清楚。
    【解决方案3】:

    如果您可以控制崩溃代码,那么我还建议您更改代码以其他方式死掉。如果你不这样做,你可以尝试安装一个空的信号处理程序(即使用signal(SIGFPE, &amp;EmptyFunction)),但你仍然依赖于未定义的行为,所以不能保证它仍然可以在其他系统或其他内核上工作或 C 库版本。

    【讨论】:

      【解决方案4】:

      检查返回值

      signal(SIGFPE, SIG_IGN);
      

      如果您得到SIG_ERR,请检查errno 的值以找出问题所在。这就是您可以随身携带的尽可能多的东西。

      我知道您不想更改除以零,但它不便携且违反直觉。如果发生某些情况,您想进行核心转储,但能够在不编辑代码的情况下禁用此行为?使用assertNDEBUG

      【讨论】:

        【解决方案5】:

        好的,首先,您应该使用 sigaction(2) 而不是已弃用的 signal()

        其次,使用 SIGFPE 来终止程序显然是荒谬的,因为您应该发出 SIGTERM 或 SIGUSR1 之类的信号,而不是因为它的副作用而对其他信号进行陪审团操纵而无视其语义价值。更具体地说,sigaction(2) 的手册页有一个 NOTES 部分,其中包含一个关于 SIGFPE 的简介,表明您对它的预期用途被破坏的一种或两种方式。

        你应该做的是raise(3)一个信号,当你想终止。然后,使用sigaction 结构中的sa_handler 字段来更改是忽略(SIG_IGN)还是终止(SIG_DFL)该信号。

        诠释主要(无效){ 结构 sigaction my_action; my_action.sa_handler = SIG_IGN; my_action.sa_flags = SA_RESTART; sigaction(SIGUSR1, &my_action, NULL); 提高(SIGUSR1); /* 忽略 */ my_action.sa_handler = SIG_DFL; sigaction(SIGUSR1, &my_action, NULL); 提高(SIGUSR1); /* 终止 */ 返回0; }

        也就是说,我不明白你为什么要使用信号而不是简单的exit()

        【讨论】:

          【解决方案6】:

          你能通过一个不那么做作的表达式让程序退出吗?例如:

          #include <signal.h>
          
          #ifdef DEBUG
          #define DIE_HERE raise(SIGFPE)
          #else
          #define DIE_HERE
          #endif
          

          我会犹豫是否要覆盖默认行为,以免程序的其他部分无意中除以零。或者,如果您强制它以这种方式退出以获取核心转储,您可能需要考虑在调试器中使用断点。或者,如果您使用的是带有 gdb 调试器的系统,那么 gcore 实用程序可能会很有用。

          【讨论】:

            【解决方案7】:

            这不是可移植的,但在 x86 上您可以通过控制 FPU:

            在 Linux 上使用 gcc(我相信其他编译器也有类似的功能):

            #include <fpu_control.h>
            
            _FPU_SETCW (_FPU_DEFAULT);
            

            因为 _FPU_DEFAULT 默认设置为 _FPU_MASK_ZM(ZM 代表 Zero-Divide-Mask)。

            【讨论】:

              【解决方案8】:

              为什么要故意除以零来停止?你不能exit(-1) 或类似的吗?

              特别是如果您不需要除以 0 的结果,这没有任何意义。

              【讨论】:

              • 因为它是用于嵌入式设备中通常使用的代码;在大多数情况下,我想停止设备并让看门狗重新启动
              • 有什么原因不能发送 SIGQUIT 而不是除以零?
              • 对于这个特定的测试,我简单地删除了除以零并使用了不同的实现。对于嵌入式应用程序,我仍然使用除以零(大多数平台不是 POSIX),但我没有禁用它的要求。
              猜你喜欢
              • 2016-08-23
              • 2011-11-08
              • 1970-01-01
              • 2019-03-21
              • 1970-01-01
              • 1970-01-01
              • 2011-02-23
              • 1970-01-01
              • 2016-10-05
              相关资源
              最近更新 更多