4

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

有没有办法忽略它?

我试过使用

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

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

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

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

4

8 回答 8

6

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

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

当您想终止时,您应该做的是raise(3)一个信号。然后,使用结构中的sa_handler字段sigaction来更改是忽略 ( 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().

于 2009-01-07T09:00:07.243 回答
4

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

尤其是如果您不需要除以 0 的结果,这是没有意义的。

于 2009-01-07T08:09:53.993 回答
2

检查返回值

signal(SIGFPE, SIG_IGN);

如果得到SIG_ERR,请检查 的值errno以找出问题所在。这就是您可以便携地做的尽可能多的事情。

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

于 2009-01-07T09:06:30.070 回答
1

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

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

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

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

于 2009-01-07T08:22:49.427 回答
1
void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);
于 2012-05-22T12:39:57.053 回答
0

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

#include <signal.h>

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

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

于 2009-01-07T08:30:02.813 回答
0

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

于 2009-01-07T09:55:14.577 回答
0

lnmiit l over the crashing code,那么我还建议更改代码以其他方式死掉。如果你不这样做,你可以尝试安装一个

于 2012-02-16T09:54:19.963 回答