如何将SIGFPE与信号一起使用
How to use SIGFPE with signal?
我只是告诉myselve关于C/C++中的"信号"并玩了一下。但是我有一个问题来理解SIGFPE
的逻辑.
我写了一个小程序,它将被零除,如果发生这种情况,那么应该触发信号并执行信号处理程序。但相反,我的程序只是崩溃。那么,如果SIGFPE
甚至不能除以零,那么它的目的是什么?
#include <stdio.h>
#include <signal.h>
#include <iostream>
int signal_status = 0;
void my_handler (int param)
{
signal_status = 1;
printf ("DIVISION BY ZERO!");
}
int main ()
{
signal (SIGFPE, my_handler);
int result = 0;
while(1)
{
system("cls");
printf ("signaled is %d.n", signal_status);
for(int i=10000; i>-1; i--)
{
result = 5000 / i;
}
}
getchar();
return 0;
}
正如我评论的那样,大多数信号都是特定于操作系统的。对于 Linux,请仔细阅读 signal(7(。你忘记了printf
里面的n
(通常,你会很幸运地看到你的代码中有一些东西在工作,但请阅读我所有的答案(。原则上你不应该从你的信号处理程序调用printf
(这不是一个异步信号安全的函数,你应该直接使用,并且只在里面写(2(。
可能正在发生的事情是(忽略在信号处理程序中错误使用printf
所带来的未定义行为(是:
-
您的
stdout
缓冲区永远不会刷新,因为您忘记了代码内部my_handler
printf
中的n
(您可能会添加fflush(NULL);
...( -
SIGFPE 处理程序可能会再次重新启动触发它的机器代码指令。(更确切地说,从 sigreturn(2( 返回后,您的机器处于与交付
SIGFPE
之前相同的状态,因此会发生相同的除以零条件,等等...
处理SIGFPE
是很困难的(但非常痛苦,如果你接受编码特定于硬件和操作系统的代码(;你可以将 sigaction(2( 与 SA_SIGINFO
一起使用,并将第三个参数处理到信号处理程序(这是一个间接提供机器状态的ucontext_t
指针,包括处理器寄存器,你可以在处理程序中更改它;特别是你可以在那里更改你的返回程序计数器(。你也可以考虑在信号处理程序中使用 sigsetjmp(3( (但理论上这是被禁止的,因为不是异步信号安全的(。
(你当然需要了解处理器的指令集架构和操作系统的ABI的细节;在掌握这些之后,你可能需要一周的编码工作(
以便携式POSIX的方式,SIGFPE
无法真正处理,正如Blue Moon的回答中所解释的那样
可能,JVM或SBCL的运行时正在以机器和操作系统特定的方式处理SIGFPE
,以将零除报告为除以零异常。(JVM的Java程序,SBCL的Common Lisp程序(。或者,他们的 JIT 或编译器机制可以在每个部门之前生成一个测试。
顺便说一句,信号处理程序内设置的标志应该声明为volatile sig_atomic_t
。查看有关<signal.h>
的 POSIX 规范
作为一个实用的经验法则,POSIX 可移植且健壮的信号处理程序应该只设置一些volatile sig_atomic_t
和/或可能将(2(几个字节写入某个管道(7((您的进程可以为自己设置一个管道 - 正如Qt所推荐的那样-,另一个线程和/或某个事件循环读取它(,但这不适用于异步进程生成的信号,如SIGFPE
, SIGBUS
、SIGILL
、SIGSEGV
等...(这只能通过痛苦的计算机特定代码来处理(。
另请参阅对一个非常相关的问题的回答。
最后,在Linux上,信号处理被认为不是很快。即使有很多特定于机器的编码,通过棘手的SIGSEGV
处理来模拟GNU Hurd外部寻呼机(这会懒惰地mmap
......(被认为是相当慢的。
零是未定义的行为。因此,当您的程序调用未定义的行为时,您是否安装了用于SIGFPE
的处理程序意义不大。
波西克斯 说:
信号信号的传递对过程没有影响。这 进程的行为在忽略 SIGFPE、SIGILL 、 SIGSEGV,或不是由kill((生成的SIGBUS信号, sigqueue((,或 raise((。
因事件(例如,通过按 CTRL+C 发送SIGINT
(而引发,如果所述事件非致命,则进程可以处理该信号。 SIGFPE
是程序中的错误条件,您无法处理。类似的情况是尝试处理SIGSEGV
,这等同于这个(未定义的行为(。当您的进程尝试访问某些它无权访问的内存时。如果你可以忽略它并继续前进,就好像什么都没发生一样,那将是愚蠢的。
- Qt VTK交互风格的信号到小部件
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何将enable-if与模板参数和参数包一起使用
- 如何将PERF_AMPLE_READ与mmap一起使用
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- 如何在没有信号的情况下从C++执行QML插槽
- 如何将C++中的库和头与MinGW一起使用
- 线程之间的布尔停止信号
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 为什么我不能将 rand() 与数组的大小一起使用?
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 将fold表达式与std::一起用于两个元组
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- 替换 QObject 与信号和插槽一起使用时的异常
- 有没有一种方法可以将升压信号和插槽与不可复制的对象一起使用
- 如何将模板与QT信号和插槽一起使用
- 如何将SIGFPE与信号一起使用
- 将OSG的osgViewerQt示例与Qt信号/插槽一起使用