否定INT_MIN是否为不确定行为?

Son*_*Ex2 3 c c99 c89 undefined-behavior

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

int i = get_i();
Run Code Online (Sandbox Code Playgroud)

假设iINT_MIN和的补码表示形式,是-i不确定的吗?

nwe*_*hof 11

这取决于平台。C支持负数的三种表示形式(请参阅C99标准的6.2.6.2节):

  • 补码。
  • 一个人的补充。
  • 符号和大小。

用一个人的补语,符号和大小-INT_MIN来定义(并等于INT_MAX)。对于二进制补码,它取决于符号位为1且所有值位为零的值是陷阱表示形式还是正常值。如果是正常值,则会-INT_MIN溢出,从而导致不确定的行为(请参阅C99标准的6.5节)。如果是陷阱表示,则-INT_MIN等于INT_MAX

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


sup*_*cat 5

平台可以选择定义行为,但 C 标准不要求它们对此做出任何保证。虽然历史上微型计算机编译器的行为相对一致,就好像 -INT_MIN 会生成 INT_MIN,或者在某些情况下会生成一个比 INT_MAX 大一的值,但更流行的是让它追溯性地更改被否定的值。因此,给出:

int wowzers(int x)
{
  if (x != INT_MIN) printf("Not int min!");
  return -x;
}
Run Code Online (Sandbox Code Playgroud)

超现代编译器可以使用表达式 -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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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