[英]How to use SIGFPE with signal?
我只是告诉自己有关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
(这不是异步信号安全函数,您应该直接使用它,而只能在内部使用write(2) )。
可能发生的是(忽略由于错误使用信号处理程序中的printf
造成的未定义行为 ):
您的stdout
缓冲区永远不会刷新,因为您在代码中my_handler
内的printf
忘记了\\n
(可能会添加fflush(NULL);
...)
可能是SIGFPE处理程序再次重新启动了触发它的机器代码指令。 (更确切地说,从sigreturn(2)返回之后,您的计算机与交付SIGFPE
之前的状态相同,因此发生了相同的被零除的情况,等等。)
处理SIGFPE
很难(但很痛苦,如果您接受对硬件和操作系统特定的代码的编码); 您可以将sigaction(2)与SA_SIGINFO
一起SA_SIGINFO
并处理信号处理程序的第三个参数(这是ucontext_t
指针,它间接提供机器状态,包括处理器寄存器 ,您可以在处理程序内部进行更改;特别是可以更改返回程序柜台那里)。 您可能还会考虑在信号处理程序中使用sigsetjmp(3) (但是从理论上讲,这是禁止的,因为它不是异步信号安全的)。
(您当然需要了解处理器的指令集体系结构和操作系统的ABI的详细信息 ;掌握这些知识后,可能需要一周的编码工作)
如Blue Moon的答案所述 ,以便携式POSIX方式无法真正处理SIGFPE
可能是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上,信号处理被认为不是很快。 即使有很多具体的机器编码,模拟GNU赫德外部寻呼机通过棘手的SIGSEGV
处理(这将mmap
懒洋洋....)被认为是相当缓慢。
除以零是未定义的行为 。 因此,当程序调用未定义的行为时,是否为SIGFPE
安装处理程序就没有什么意义。
POSIX说:
信号的传递对过程没有影响。 忽略不由kill(),sigqueue()或raise()生成的SIGFPE,SIGILL,SIGSEGV或SIGBUS信号后,进程的行为是不确定的。
由于事件(例如,通过按CTRL + C发送SIGINT
)而引发SIGINT
, 如果该事件不致命,则可由该进程处理。 SIGFPE
是程序中的错误情况,您无法处理 。 类似的情况是尝试处理SIGSEGV
,这等效于此(未定义的行为)。 当您的进程尝试访问一些它没有访问权限的内存时。 如果您只是忽略它并继续进行,好像什么都没有发生,那将是愚蠢的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.