信号处理程序正在返回触发它的指令,即*a = 5,这导致它循环。
您有几个问题,包括在信号处理程序中使用printf。
有安全和不安全的处理方法
注意事项
一般不建议使用signal(2) 进行信号处理。
由于信号语义的工作方式,处理SIGSEGV 更加复杂。从手册页引用:
signal() 的唯一可移植用途是将信号的处置设置为 SIG_DFL 或 SIG_IGN。使用 signal() 时的语义
建立一个信号处理程序
系统(并且 POSIX.1 明确允许这种变化);请勿将其用于此目的。
POSIX.1 通过指定 sigaction(2) 解决了可移植性的问题,当一个
调用信号处理程序;使用该接口而不是 signal()。
所以你应该做的第一件事是使用sigaction。
接下来,处理 SIGSEGV 是一头怪事:
How to write a signal handler to catch SIGSEGV?
和
Does linux allow any system call to be made from signal handlers?
有好的答案并深入了解具体细节。那里给出的一些答案中有外部链接。
如何使用信号 (2) 来做到这一点
嗯 :-) 假设你 想要 使用 signal(2) 并且你想要以一种奇怪的方式玩这个....
您可以使用sigjmpset 和siglongjmp。
sigjmpset 标记了siglongjmp 应该跳转到的点。第一次调用sigjmpset(设置点)返回0。当siglongjmp 跳转到它时,(这意味着由于长跳转而再次调用它),它返回1。
这意味着我们可以这样做:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
sigjmp_buf env;
int sigsav;
void sighandler(int signum)
{
const char msg[] = "Skipping signal\n";
write(2, msg, sizeof(msg));
siglongjmp(env, sigsav);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
if(!sigsetjmp(env, sigsav)) {
printf("setting value of a\n");
*a = 5;
}
else {
printf("returned to sigsetjmp, but now we skip it!\n");
}
return 0;
}