什么是C/C++处理程序SIGFPE

what does C/C++ handler SIGFPE?

本文关键字:处理 程序 SIGFPE C++ 什么      更新时间:2023-10-16

好吧,我已经搜索了关于SIGFPE的文章,然后我写了一些测试,但它的行为很奇怪。然后我不得不把它贴在这里寻求帮助。GCC/G++或ISO C++是否明确定义了如果除以零会发生什么?

1) 我搜索了这篇文章:除以零不会引发SIGFPE它的输出是inf

2) 如果我重写如下:

void signal_handler (int signo) {
    if(signo == SIGFPE) {
      std::cout << "Caught FPEn";
    }
}
int main (void) {
  signal(SIGFPE,(*signal_handler));
  int b = 1;
  int c = 0;
  int d = b/c;
  //fprintf(stderr,"d number is %dn,d);
  return 0;
}

则不会发生signal_handler。但是如果我取消注释行

//fprintf(stderr,"d number is %dn,d);

然后signal_handler继续调用。

有人能解释一下吗?

这很有趣:当fprintf被注释掉时,编译器已经确定计算结果:d = b/c是一个未使用的局部表达式,可以进行优化。

很明显,它在执行过程中并不是没有副作用的,但编译器在这个阶段无法确定任何关于运行时环境的信息。我很惊讶静态分析在现代编译器中(至少)没有把这当成一个警告。

@冯布兰德是对的。您很幸运在(异步)信号处理程序中所做的工作。


编辑:当你说"signal_handler一直在呼叫"时,你的意思是它无限期地重复吗?如果是这样,那么重新启动底层系统调用可能会出现问题。尝试:siginterrupt(SIGFPE, 1);(假设它可用)。

信号处理程序中只允许少数操作,使用任何缓冲I/O(std::cout等,还有fprintf(3),BTW我不知道它是否与前一个混合良好)都是不可能的。有关限制,请参见signal(7)

为什么signal_handler不会发生:编译器优化为未使用的结果杀死了除法。

为什么signal_handler不断调用:从信号处理程序返回后,FPE重新执行相同的指令。您可以通过使用longjmp来避免它。

以下是我为此目的编写的运行良好的代码(至少在Mac OS X上)https://github.com/nishio/learn_language/blob/master/zero_division/zero_division.cpp

GCC/G++或ISO C++是否明确定义了如果除以零会发生什么?

就标准而言,除以零就是未定义的行为,任何事情都可能发生。

在实践中,尽管标准说它是UB,但它实际上是在操作系统(而不是语言/编译器)级别定义的实现。在POSIX上,这确实会生成一个SIGFPE,在Windows上,它会抛出一个异常(Windows的SEH异常,而不是C++异常,尽管一些编译器还将SEH映射到C++异常),等等。

如果我取消对//fprintf(stderr,"d number is %dn,d);行的注释,那么signal_handler将继续调用。有人能解释一下吗?

正如其他人所说,这是因为编译器检测到从未使用过d,并优化了计算(以及bc的定义)。发生这种情况是因为语言无法预见会发生什么(记住,它是UB),所以它还不如假设什么都没有发生。