1

我从用不同版本编译的可执行文件中得到了这种奇怪的行为gcc,都发出SIGFPE信号,最好的部分是我的代码中没有任何类型的浮点;如果有人能对此有所了解......我真的不知道从哪里开始调试这个,这太奇怪了,这个错误是由我从4.9to的所有 gcc 安装触发的6.0

这是重现问题的片段

// Floating point exception - SIGFPE
#include <stdio.h>
typedef unsigned int T;
int main()
{
#define N 256 
  for (T i = 0; i < N; ++i)
    {
      i += (i % i);
      printf("%u\t", i);
    }
}
// bug uncovered with
// gcc version 4.9.2 (Debian 4.9.2-10)
// gcc version 5.1.0 (GCC)
// gcc version 6.0.0 20150517 (experimental) (GCC)
// using -std=c11 or -std=c99

这段代码的目的是重现问题,我知道它的逻辑并没有太大意义(取模部分)但clang通过了测试,没有版本gcc相同,我想知道为什么如果这种行为有技术解释。

4

2 回答 2

2

运行代码后,这是在cygwin下,gdb转储了trace。

$ cat sigfpe.exe.stackdump
Exception: STATUS_INTEGER_DIVIDE_BY_ZERO at rip=00100401115
rax=0000000000000000 rbx=000000000022CB20 rcx=0000000000000001
rdx=0000000000000000 rsi=000000060003A2F0 rdi=0000000000000000
r8 =0000000000000000 r9 =0000000000000000 r10=0000000000230000
r11=0000000000000002 r12=0000000000000000 r13=0000000000000001
r14=000000000022CB63 r15=000000000022CB64
rbp=000000000022CAD0 rsp=000000000022CAA0
program=C:\cygwin64\home\luser\sigfpe.exe, pid 6808, thread main
cs=0033 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame        Function    Args
0000022CAD0  00100401115 (00000000020, 30001000000FF00, 0018004830F, 0000022D680                                                                                                                )
0000022CBC0  00180048380 (00000000000, 00000000000, 00000000000, 00000000000)
00000000000  0018004607C (00000000000, 0003E704021, 00000000000, 0000000002D)
00000000000  00180046114 (00000000000, 00000000000, 00000000000, 00000000000)
00000000000  00100401191 (00000000000, 00000000000, 00000000000, 00000000000)
00000000000  00100401010 (00000000000, 00000000000, 00000000000, 00000000000)
00000000000  000772E59CD (00000000000, 00000000000, 00000000000, 00000000000)
00000000000  0007741B981 (00000000000, 00000000000, 00000000000, 00000000000)
End of stack trace

线索在行动中i += (i % i)

当循环初始值为0时,当然除以零错误。

你试过捕捉信号吗?

查看第 265 页的C11 标准, SIGFPE -错误的算术运算,例如零除或导致溢出的操作

这不是编译器错误,而是实现定义的。

于 2015-06-03T23:47:57.557 回答
0

如果恶魔在使用未定义行为 (UB) 时爬上您的键盘,请不要抱怨:

C11 草案,6.5.5#5:“/ 运算符的结果...... % 运算符的结果是余数。在这两个操作中,如果第二个操作数的值为零,则行为未定义。”

UB可以是任何东西。您实际上应该很高兴得到一个异常,无论它被称为什么(它实际上甚至显示了正确的原因),而不仅仅是让程序产生错误的结果而不被注意到(实际上可能发生的最糟糕的情况!)。对于许多 CPU,您不会注意到任何东西。只需启用编译器警告;这可能有助于发现此类情况(但不能保证)。

于 2015-06-04T00:18:36.440 回答