好吧,我搜索了有关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继续打电话。
有人可以解释一下吗?
答案 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
从未使用过并且优化了计算(以及所有概率的b
和c
定义)。发生这种情况是因为语言不能预见会发生什么(记住,它是UB)所以它也可能假设没有任何反应。