为什么这段代码会导致浮点异常 - SIGFPE

4

使用gcc 4.7:

$ gcc --version
gcc (GCC) 4.7.0 20120505 (prerelease)

代码清单(test.c):

#include <stdint.h>

struct test {
    int before;

    char start[0];
    unsigned int v1;
    unsigned int v2;
    unsigned int v3;
    char end[0];

    int after;
};

int main(int argc, char **argv)
{
  int x, y;

  x = ((uintptr_t)(&((struct test*)0)->end)) - ((uintptr_t)(&((struct test*)0)->start));
  y = ((&((struct test*)0)->end)) - ((&((struct test*)0)->start));

  return x + y;
}

编译和执行

$ gcc -Wall -o test test.c && ./test
Floating point exception

SIGFPE是由第二个赋值语句(y = ...)引起的。在汇编列表中,该行存在除法运算符?请注意,x=和y=之间唯一的区别是强制转换为(uintptr_t)。


GCC探索器输出:http://preview.tinyurl.com/8ah2fa7 - Wade
3
char start[0]; 意味着你已经超出了标准定义的范围。在那之外发生的事情,真的那么有趣吗? - Daniel Fischer
1个回答

8

忽略标准中由于违反约束条件而导致的未定义行为,gcc 在这里所做的是计算两个指向 char[0] 的指针之间的差值 - &(((struct test*)0)->start)&(((struct test*)0)->end),并将该差值除以 char[0] 的大小,当然其大小为0,因此会得到一个除以0的结果。


出于历史原因,在UNIX中,整数除以0会产生浮点异常(SIGFPE信号)。 - ouah
那是UNIX(和衍生系统)的特色吗?我以为那是x86的东西。 - Daniel Fischer
好问题。我知道在UNIX上x86是这种情况,但我不确定其他系统是否也是如此。 - ouah
@ninjalj 我敢打赌,一些使用更加奇特的处理器的UNIX系统在汇编指令除以0时可能会出现未定义行为,并且实际上可能会随机响应。 - ouah
关于C和POSIX要求。 C不需要实现发出SIGFPE信号(例如在整数除以零时)(C11,7.11p4)“实现不需要生成这些信号中的任何一个,除非是显式调用raise函数的结果”并且POSIX也是如此:请参见此POSIX接受的解决缺陷,以澄清情况:http://austingroupbugs.net/view.php?id=536 - ouah
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接