【问题标题】:Is negating INT_MIN undefined behaviour?是否否定 INT_MIN 未定义的行为?
【发布时间】:2016-09-15 00:38:26
【问题描述】:

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

int i = get_i();

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

【问题讨论】:

  • 回答 2 对您有帮助 stackoverflow.com/questions/8917233/…
  • 如果你试图生成一个它的类型不能表示的右值,那么它就是UB。
  • 简短回答:是的,这是未定义的行为。下面的答案提供了很好的细节,但有点绕圈子。

标签: c c99 undefined-behavior c89


【解决方案1】:

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

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

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

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

【讨论】:

  • 最后一段我似乎不清楚,我想你是想说如果INT_MIN == -INT_MAX 那么-INT_MIN == INT_MAX,否则-INT_MIN 是未定义的行为
  • @M.M 我想说的是INT_MIN == -INT_MAX 在什么条件下是正确的,而且这个条件甚至可以在二进制补码平台上成立(至少在理论上)。
  • 我花了一些时间在 6.2.6.2 和 6.5 节的错误部分寻找-INT_MIN 是未定义行为的声明。我最终确实找到了它(我认为),在第 6.5-5 项中,它说“如果在评估表达式期间发生异常情况(也就是说,如果结果没有在数学上定义或不在可表示的值范围内)它的类型),行为是未定义的。”
  • @pnkfelix 仅在 -INT_MIN 超出整数可以表示的值范围时才重要。如果您使用符号幅度或补码,-INT_MIN 在整数可以表示的值范围内,因此-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 特性来“优化”以下内容

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

【讨论】:

  • 你有支持超现代编译器假设的证据吗?
  • @YatharthAgarwal:我已经确定了某些情况下,对可能导致某些参数值溢出的表达式求值将导致编译器推断不会接收此类参数。我还没有在今天的编译器中发现特别是 INT_MIN 的否定会导致这种情况的情况,但是像 gcc 这样的编译器的作者非常清楚地表明,在标准没有强制要求并且没有明确记录的情况下,他们不会对未来的行为做出任何承诺.
  • @YatharthAgarwal:我添加了一个函数示例,其中尝试在 gcc 8.2 中取反等于 INT_MIN 的值会影响另一个对象的存储值。
  • 哇——好例子!
  • @YatharthAgarwal:如果将q 更改为-2147483646-i,编译器的行为会更有趣。生成的代码最终效率低于将rr=-rr 行替换为rr=-(unsigned)rr 的情况,因此编译器对UB 的处理甚至不会提高代码效率。
【解决方案3】:

是否否定 INT_MIN 未定义的行为?

是的,当INT_MIN &lt; -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

【讨论】:

  • 可能不重要,但fprintf( 需要); 之前。
  • @EsmaeelE 是的,代码已修改。
猜你喜欢
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
  • 2014-06-10
  • 2013-04-25
相关资源
最近更新 更多