7

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

1)我搜索了文章: 除以零不会抛出 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

4 回答 4

5

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

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

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


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

于 2013-02-16T01:38:42.777 回答
3

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

于 2013-02-16T01:35:41.653 回答
3

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

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

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

于 2014-05-19T02:41:43.343 回答
1

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),所以它不妨假设什么都没有发生。

于 2013-02-16T03:40:31.517 回答