【问题标题】:what does C/C++ handler SIGFPE?C/C++ 处理程序 SIGFPE 是什么?
【发布时间】:2013-02-01 02:12:18
【问题描述】:

好吧,我已经搜索了有关 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 继续调用。

谁能解释一下?

【问题讨论】:

  • 整数除以零仍然会引发SIGFPE(浮点错误),但浮点除以零会产生无穷大作为答案。
  • int c = 0; int d = b/c; ?这意味着b/0 ?
  • 我并没有完全复制你:我只收到一次信号,然后程序退出,有或没有printf。如果我在信号处理程序中添加signal(SIGFPE,(*signal_handler));,那么我会重现你。 Linux 3.10,gcc 4.7.3。

标签: c++ signals sigfpe


【解决方案1】:

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

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

@vonbrand 是对的。您在(异步)信号处理程序中所做的事情很幸运。


编辑:当您说“signal_handler 不断调用”时,您的意思是它无限期地重复吗?如果是这样,则可能存在底层系统调用重新启动的问题。试试:siginterrupt(SIGFPE, 1);(假设它可用)。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 似乎也适用于g++clang++ ubuntu
      【解决方案4】:

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2011-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-07
        • 2016-05-08
        相关资源
        最近更新 更多