C 为什么在用户';s信号处理器

C 为什么在用户';s信号处理器,c,concurrency,signals,C,Concurrency,Signals,调试下一个代码段时,调试器返回到带有x=5的行x=10/x,仍然会得到一个SIGFPE #include <signal.h> volatile sig_atomic_t x = 0; void sigfpe_handler(int signum) { x = 5; // Notice that there is no exit() } int main() { signal(SIGFPE, sigfpe_handler); x = 10 / x;

调试下一个代码段时,调试器返回到带有
x=5
的行
x=10/x
,仍然会得到一个
SIGFPE

#include <signal.h>

volatile sig_atomic_t x = 0;

void sigfpe_handler(int signum) {
    x = 5;

  // Notice that there is no exit()
}

int main() {
    signal(SIGFPE, sigfpe_handler);
    x = 10 / x;
    return 0;
}
#包括
挥发性sig_原子x=0;
无效sigfpe_处理程序(int signum){
x=5;
//请注意,没有出口()
}
int main(){
信号(SIGFPE,SIGFPE_处理器);
x=10/x;
返回0;
}
  • 这里发生了什么
  • 处理程序实际返回到哪一点

为正常返回的
SIGFPE
安装一个信号处理程序,然后执行一些操作,使系统生成该信号

从POSIX规范:

进程的行为在正常情况下从不是由kill()、sigqueue()或raise()生成的SIGBUS、SIGFPE、SIGILL或SIGSEGV信号的信号捕获函数返回后是未定义的

C标准中也有类似的措辞。所以接下来发生的事情是无法控制的,因为它是未定义的行为。您的程序可能会继续,可能会进入无限循环,等等


此外,如果您希望在处理程序中对变量所做的更改能够可靠地、可移植地显示在处理程序之外,那么您的
x
变量需要是
volatile sig_atomic_t
类型(假设所述处理程序不会像本例中那样导致未定义的行为)。C11无锁原子类型也可以。

如前所述,这在技术上是未定义的行为

发生的情况是,
SIGFPE
重复出现。如果从信号处理程序添加打印语句,则可以看到:

#include <signal.h>

volatile sig_atomic_t x = 0;

void sigfpe_handler(int signum) {
    x = 5;
    write(2, "Received SIGFPE\n", sizeof "Received SIGFPE\n" - 1 );
}

int main() {
    signal(SIGFPE, sigfpe_handler);
    x = 10 / x;
    return 0;
}
如果您注意到,
x
的值已经加载到寄存器中,这就是它所使用的。这就是为什么对
x
的更改没有达到预期效果的原因

您可以执行“跳转”,然后跳过导致FPE的代码:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <setjmp.h>

sigjmp_buf jbuf;

volatile sig_atomic_t x = 0;

void sigfpe_handler(int signum) {
    x = 5;
    write(2, "Received SIGFPE\n", sizeof "Received SIGFPE\n" - 1 );
    siglongjmp(jbuf, 1);
}

int main() {
    signal(SIGFPE, sigfpe_handler);
    if (sigsetjmp(jbuf, 0) == 0)
        x = 10 / x;
    else
        printf("Returned from siglongjmp\n");
    return 0;
}
#包括
#包括
#包括
#包括
sigjmp_buf jbuf;
挥发性sig_原子x=0;
无效sigfpe_处理程序(int signum){
x=5;
写入(2,“接收到的SIGFPE\n”,sizeof“接收到的SIGFPE\n”-1);
siglongjmp(jbuf,1);
}
int main(){
信号(SIGFPE,SIGFPE_处理器);
if(sigsetjmp(jbuf,0)==0)
x=10/x;
其他的
printf(“从siglongjmp返回\n”);
返回0;
}
有关注意事项,请阅读手册

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <setjmp.h>

sigjmp_buf jbuf;

volatile sig_atomic_t x = 0;

void sigfpe_handler(int signum) {
    x = 5;
    write(2, "Received SIGFPE\n", sizeof "Received SIGFPE\n" - 1 );
    siglongjmp(jbuf, 1);
}

int main() {
    signal(SIGFPE, sigfpe_handler);
    if (sigsetjmp(jbuf, 0) == 0)
        x = 10 / x;
    else
        printf("Returned from siglongjmp\n");
    return 0;
}