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

时间:2013-02-16 01:25:13

标签: c++ signals sigfpe

好吧,我搜索了有关SIGFPE的文章,然后我写了一些测试,但它的行为很奇怪。然后我必须在这里发帖寻求帮助。 GCC / G ++或ISO C ++是否清楚地定义了如果除以零会发生什么?

1)我搜索了这篇文章: Division by zero does not throw SIGFPE 同样输出是inf

2)如果我按以下方式重写它:

void signal_handler (int signo) {
    if(signo == SIGFPE) {
      std::cout << "Caught FPE\n";
    }
}

int main (void) {
  signal(SIGFPE,(*signal_handler));

  int b = 1;
  int c = 0;
  int d = b/c;
  //fprintf(stderr,"d number is %d\n,d);
  return 0;
}

然后signal_handler将不会发生。但如果我取消注释该行

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

然后signal_handler继续打电话。

有人可以解释一下吗?

4 个答案:

答案 0 :(得分:5)

这很有趣:在fprintf注释掉后,编译器已确定计算结果:d = b/c是未使用的本地表达式,可以进行优化。

显然,它在执行时没有副作用,但编译器无法在此阶段确定有关运行时环境的任何信息。我很惊讶静态分析不会在现代编译器中将其作为警告(至少)。

@vonbrand是对的。你很幸运,你在(异步)信号处理程序中正在做什么。


编辑:当你说“signal_handler一直在呼唤”时,你的意思是它无限期重复吗?如果是这样,可能会出现重启基础系统调用的问题。尝试:siginterrupt(SIGFPE, 1);(假设它可用)。

答案 1 :(得分:3)

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

答案 2 :(得分:3)

为什么signal_handler不会发生:编译器优化会因未使用的结果而导致分裂。

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

这是我用于此目的的良好代码(至少在Mac OS X上) https://github.com/nishio/learn_language/blob/master/zero_division/zero_division.cpp

答案 3 :(得分:1)

  

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

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

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

  

如果我取消注释行//fprintf(stderr,"d number is %d\n,d);,那么signal_handler会继续调用。有人可以解释一下吗?

正如其他人所说的那样,这是因为编译器检测到d从未使用过并且优化了计算(以及所有概率的bc定义)。发生这种情况是因为语言不能预见会发生什么(记住,它是UB)所以它也可能假设没有任何反应。