否定INT_MIN未定义的行为?

时间:2016-05-18 13:27:30

标签: c c99 undefined-behavior c89

假设我有一个来自外部来源的变量i

int i = get_i();

假设iINT_MIN和两个补码表示,-i是否未定义?

3 个答案:

答案 0 :(得分:6)

这取决于平台。 C支持负数的三种表示(参见C99标准的section 6.2.6.2):

  • 两个补充。
  • 补充。
  • 签名和数量。

使用补码和符号和幅度,-INT_MIN被定义(并且等于INT_MAX)。使用二进制补码时,它取决于符号位1和所有值位零的值是陷阱表示还是正常值。如果它是正常值,-INT_MIN溢出,导致未定义的行为(请参阅C99标准的section 6.5)。如果它是陷阱表示,-INT_MIN等于INT_MAX

也就是说,大多数现代平台使用两个补码而没有陷阱表示,因此-INT_MIN通常会导致未定义的行为。

答案 1 :(得分:2)

平台可以选择定义行为,但C标准不要求他们保证任何相关内容。虽然历史上微型计算机编译器的行为相对一致,但-INT_MIN会产生INT_MIN,或者在某些情况下表现的行为类似于大于INT_MAX的值,因此将追溯更改为更为时尚任何被否定的价值。因此,给出:

int wowzers(int x)
{
  if (x != INT_MIN) printf("Not int min!");
  return -x;
}

超现代编译器可以使用表达式-x来确定x是否可以 在执行先前的比较时,它等于INT_MIN,并且 因此可以无条件地执行printf。

顺便说一句,gcc 8.2将使用否定INT_MIN的UB-ness来优化"以下

int qq,rr;
void test(unsigned short q)
{
    for (int i=0; i<=q; i++)
    {
        qq=-2147483647-i;
        rr=qq;
        rr=-rr;
    }
}

代码无条件地将-2147483647存储到qq和2147483647到rr。删除rr=-rr行将使代码存储为-2147483647或-2147483648 qqrr,具体取决于q是否为零。

答案 2 :(得分:0)

  

否定INT_MIN未定义的行为?

是的,当INT_MIN < -INT_MAX-非常很常见(2的补码)时。这是整数溢出

int i = get_i();

#if INT_MIN < -INT_MAX
if (i == INT_MIN) {
  fprintf(stderr, "Houston, we have a problem\n";
  // Maybe return or exit here.
}
#endif 

int j = -i;

Houston, we have a problem