INT_MIN%-1是否会产生未定义的行为?

时间:2011-05-08 01:19:03

标签: c gcc overflow division modulo

gcc生成浮动代码,为以下代码引发SIGFPE

#include <limits.h>
int x = -1;
int main()
{
    return INT_MIN % x;
}

但是我在标准中找不到这个代码调用未定义或实现定义的行为的语句。据我所知,它需要返回0.这是gcc中的错误还是我错过了标准的一些特殊例外?

5 个答案:

答案 0 :(得分:16)

您可能认为这可以被视为实际标准中的错误。 current draft解决了这个问题:

  

如果商a / b是可表示的,   表达式(a / b)* b + a%b应   等于否则,的行为   a / b和%b都未定义。

答案 1 :(得分:15)

查看gcc生成的汇编代码(x在程序集中早先定义为-1):

movl    x, %ecx
movl    $-2147483648, %eax
movl    %eax, %edx
sarl    $31, %edx
idivl   %ecx

第一个计算指令sarl,右移-2147483648 31位。这会导致-1放入%edx

执行下一个idivl。这是签名操作。让我引用描述:

  

将合并的%edx:%eax寄存器中包含的双字内容除以指定的寄存器或内存位置中的值。

所以-1:-2147483648 / -1是发生的分裂。 -1:-2147483648被解释为双字等于-2147483648(在二进制补码机器上)。现在-2147483648 / -1发生了返回2147483648。繁荣!那是INT_MAX之后的一个。


关于为什么问题,这是gcc中的错误还是我错过了标准的一些特殊例外?

在C99标准中,这是隐式UB(§6.5.5/ 6):

  

... /运算符的结果是丢弃任何小数部分的代数商.88)如果商a / b是可表示的,则表达式(a / b)* b + a%b应等于a。

无法表示

INT_MIN / -1,因此这是UB。

在C89中,%运算符是实现定义的,是否是编译器错误可以辩论。但问题是在gcc中列出:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30484

答案 2 :(得分:9)

答案 3 :(得分:4)

同样的问题在这里被称为缺陷报告

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614

不幸的是,我没有看到它在决议部分中明确说明它应该产生UB。分裂确实会产生UB,但对于%运算符来说,它并不明显。

答案 4 :(得分:3)

带负操作数的模运算结果在C89中实现定义,并在C99中由§6.5.5/ 6定义:

  

... /运算符的结果是代数商,丢弃了任何小数部分。 88)如果商a/b是可表示的,则表达式{{1} } + (a/b)*b应该等于a%b

     

88)这通常被称为“截断为零”。

对于二进制补码表示,a等于INT_MIN / -1,因此它不能表示为INT_MAX + 1而没有包装,我想实现选择让它具有爆炸性。< / p>