否定 INT_MIN 未定义的行为?

Is negating INT_MIN undefined behaviour?

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

int i = get_i();

假设iINT_MIN和二进制补码表示,-i是否未定义?

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

  • 补码。
  • 一个补码。
  • 符号和大小。

用补码和符号和大小,定义-INT_MIN(等于INT_MAX)。对于二进制补码,它取决于符号位为 1 且所有值位为零的值是陷阱表示还是正常值。如果它是一个正常值,-INT_MIN 溢出,导致未定义的行为(参见 C99 标准的 section 6.5)。如果是陷阱表示,-INT_MIN 等于 INT_MAX.

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

平台可以选择定义行为,但 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 将使用 UB-ness 否定 INT_MIN 到 "optimize" 以下

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

Is negating INT_MIN undefined behaviour?

是的,当 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