【问题标题】:Why does gcc not add tmin + tmin correctly? [duplicate]为什么 gcc 不能正确添加 tmin + tmin? [复制]
【发布时间】:2019-10-09 23:29:58
【问题描述】:

当我发现这个奇怪时,我一直在玩按位运算和二进制补码。

#include <stdio.h>
int main ()
{
    int tmin = 0x80000000;
    printf("tmin + tmin: 0x%x\n", tmin + tmin);
    printf("!(tmin + tmin): 0x%x\n", !(tmin + tmin));
}

上面的代码产生以下输出

tmin + tmin: 0x0
!(tmin + tmin): 0x0

为什么会这样?

【问题讨论】:

  • 你溢出了,所以它会导致未定义的行为。使用unsigned int
  • 您在第二行 printf 上缺少 )
  • @MooingDuck 我知道溢出,我只是感到困惑,因为第一个 printf 的输出似乎表明 tmin + tmin 为 0,但显然不是?
  • @DonThousand:程序有未定义的行为,所以任何事情都可能发生。
  • C 标准没有说int 类型中存在溢出的一个特定结果。它说,只要有int 溢出,C 实现就可以做它想做的任何事情,而且每次都可以不同。正如其他人指出但未解释的那样,这称为未定义行为,这意味着 C 标准根本不强加任何要求。在您询问的情况下,C 编译器可能只是在做“最简单”的事情。例如,编译器可以获取包含溢出的整个表达式并将其减少为 0,而不管它包含什么。

标签: c gcc twos-complement


【解决方案1】:

0x80000000 二进制是

0b10000000000000000000000000000000

当你将两个0x80000000s 加在一起时,

    |<-          32bits          ->|
  0b10000000000000000000000000000000
+ 0b10000000000000000000000000000000
------------------------------------
 0b100000000000000000000000000000000
    |<-          32bits          ->|

但是,您机器上的 int 似乎有 32 位,因此只保留了低 32 位,这意味着您的结果中的 1 被静默丢弃。这称为Integer Overflow

还请注意,在 C 中,有符号(与无符号相反,即unsigned int)整数溢出实际上是undefined behavior,这就是为什么!(tmin + tmin) 给出0x0 而不是0x1。请参阅this blog post 以了解由于另一个未定义的行为(即未初始化的变量)而导致变量同时为真和假的示例。

【讨论】:

  • 这里不解释第二种情况。
  • 我想我现在明白了我的困惑点。如果我将 tmin + tmin 的总和转换为 int,然后调用 !sum,那么它将按预期返回 1。
  • @DonThousand "如果我将 tmin + tmin 的总和转换为一个 int,然后调用 !sum,那么它将按预期返回 1。" --> 你还是没抓住重点。结果不是预期的,而是未定义的行为
  • @JL2210 确实如此,因为未定义的行为可以解释任何事情。编辑澄清。
  • @DonThousand 如果你不知道“未定义的行为”暗示了什么,那基本上就是规范的那个角落,他们不要求特定的结果。因此,如果您的操作属于未定义行为;即使根据数学定律,答案应该为零,你得到的答案可能是零,或者一,或一百万,随机数,或任何其他数字可以想到,因为它取决于运行它的计算机,以及目前正在实施的任何实施。 “未定义的行为”==“所有赌注都没有,逻辑不适用”。
猜你喜欢
  • 1970-01-01
  • 2014-11-15
  • 2015-12-08
  • 1970-01-01
  • 2019-07-23
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 2010-10-13
相关资源
最近更新 更多