我可以忽略由除零产生的SIGFPE吗?

时间:2009-01-07 08:05:09

标签: signals posix divide-by-zero sigfpe

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

有没有办法忽略它?

我尝试过使用

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

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

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

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

8 个答案:

答案 0 :(得分:6)

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

其次,使用SIGFPE来终止程序显然是荒谬的,因为你应该提出像SIGTERM或SIGUSR1这样的信号而不是陪审团操纵一些其他信号的副作用,而忽略它的语义价值。更具体地说, sigaction(2)的手册页有一个NOTES部分,其中包含一个关于SIGFPE的模糊信息,表示您打算使用它的一种或两种方式。

当你想要终止时,你应该做的是加注(3)信号。然后,使用sa_handler结构中的sigaction字段更改该信号是否忽略(SIG_IGN)或终止(SIG_DFL)。

int main(void) {
  struct sigaction my_action;

  my_action.sa_handler = SIG_IGN;
  my_action.sa_flags = SA_RESTART;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1);  /* Ignored */

  my_action.sa_handler = SIG_DFL;
  sigaction(SIGUSR1, &my_action, NULL);

  raise(SIGUSR1); /* Terminates */

  return 0;
}

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

答案 1 :(得分:4)

为什么你会刻意将零除以停止?你不能exit(-1)或等同吗?

特别是如果你不需要除以0的结果,这就没有意义了。

答案 2 :(得分:2)

检查

的返回值
signal(SIGFPE, SIG_IGN);

如果您获得SIG_ERR,请检查errno的值以找出问题所在。这就像你可以做到的一样多。

我知道你不想把除以零改变,但它是不可移植和违反直觉的。如果发生某些情况,您想要coredump,但是能够在不编辑代码的情况下禁用此行为吗?使用assertNDEBUG

答案 3 :(得分:1)

这不是便携式的,但在x86上你可以控制FPU:

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

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

由于_FPU_DEFAULT默认设置为_FPU_MASK_ZM(ZM代表零分割掩码)。

答案 4 :(得分:1)

void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);

答案 5 :(得分:0)

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

#include <signal.h>

#ifdef DEBUG
#define DIE_HERE raise(SIGFPE)
#else
#define DIE_HERE
#endif

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

lnmiit l over the crashing code,然后我还建议将代码更改为其他方式。如果不这样做,您可以尝试安装