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

发布于 2024-07-10 22:13:19 字数 459 浏览 10 评论 0原文

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

有什么办法可以忽略它吗?

我尝试过使用

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

,但它仍然死掉,并显示消息“浮点异常(核心转储)”。

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

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

I have a program which deliberately performs a divide by zero (and stores the result in a volatile variable) in order to halt in certain circumstances. However, I'd like to be able to disable this halting, without changing the macro that performs the division by zero.

Is there any way to ignore it?

I've tried using

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

but it still dies with the message "Floating point exception (core dumped)".

I don't actually use the value, so I don't really care what's assigned to the variable; 0, random, undefined...

EDIT: I know this is not the most portable, but it's intended for an embedded device which runs on many different OSes. The default halt action is to divide by zero; other platforms require different tricks to force a watchdog induced reboot (such as an infinite loop with interrupts disabled). For a PC (linux) test environment, I wanted to disable the halt on division by zero without relying on things like assert.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

罪#恶を代价 2024-07-17 22:13:19

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

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

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

Okay, first off, you ought to be using sigaction(2) instead of the deprecated signal().

Secondly, using SIGFPE for the purposes of terminating the program is patently absurd, as you should be raising a signal like SIGTERM or SIGUSR1 instead of jury-rigging some other signal for its side-effect and disregarding its semantic value. And more specifically, the man page for sigaction(2) has a NOTES section with a blurb about SIGFPE that indicates one or two ways your intended use of it is broken.

What you should do is raise(3) a signal when you want to terminate. Then, use the sa_handler field in the sigaction structure to change whether to ignore (SIG_IGN) or terminate (SIG_DFL) on that signal.

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;
}

That said, I can't see why you'd use signals instead of a simple exit().

等往事风中吹 2024-07-17 22:13:19

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

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

Why would you deliberately perform a divide by zero to halt? Couldn't you exit(-1) or some equivalent?

Especially if you don't need the result of the divide by 0, this just doesn't make sense.

小镇女孩 2024-07-17 22:13:19

检查如果收到 SIG_ERR 的返回值

signal(SIGFPE, SIG_IGN);

,请检查 errno 的值以找出问题所在。 这就是您可以随身携带的尽可能多的事情。

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

Check the return value of

signal(SIGFPE, SIG_IGN);

If you get SIG_ERR, check the value of errno to find out what went wrong. That's as much as you can do portably.

I know you don't want to change the divide by zero, but it's nonportable and counterintuitive. You want to coredump if some condition occurs, but be able to disable this behaviour without editing code? Use assert and NDEBUG.

花想c 2024-07-17 22:13:19

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

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

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

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

This is not portable, but on x86 you can by controlling the FPU:

Using gcc on Linux (I'm sure other compilers have similar facilities):

#include <fpu_control.h>

_FPU_SETCW (_FPU_DEFAULT);

Since _FPU_DEFAULT defaults to _FPU_MASK_ZM set (ZM stands for Zero-Divide-Mask).

双马尾 2024-07-17 22:13:19
void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);
void handler(int trapId)
{
   // Whatever
}

signal(SIGFPE, handler);
燃情 2024-07-17 22:13:19

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

#include <signal.h>

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

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

Could you cause the program to exit through a less contrived expression? For instance:

#include <signal.h>

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

I'd be hesitant to override the default behavior, lest some other part of your program divide by zero unintentionally. Alternatively, if you're forcing it to exit this way in order to get a core dump, you may want to look into using breakpoints within a debugger. Or, if you're on a system with the gdb debugger, the gcore utility may be useful.

无敌元气妹 2024-07-17 22:13:19

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

If you have control over the crashing code, then I'd also recommend to change the code to die some other way. If you don't, you could try to install an empty signal handler instead (i.e. use signal(SIGFPE, &EmptyFunction)), but you're still relying on undefined behaviour, so there's no guarantee it will still work on other systems, or other kernel or C library versions.

青衫负雪 2024-07-17 22:13:19

lnmiit l 解决了崩溃的代码,然后我还建议更改代码以其他方式死掉。 如果没有,您可以尝试安装

lnmiit l over the crashing code, then I'd also recommend to change the code to die some other way. If you don't, you could try to install an

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文