否定INT_MIN未定义的行为?

问题描述 投票:1回答:3

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

int i = get_i();

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

c c99 undefined-behavior c89
3个回答
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通常会导致未定义的行为。


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是否为零。


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

© www.soinside.com 2019 - 2024. All rights reserved.