【问题标题】:Bit shift with a signed int resets one bit too much带符号整数的位移位重置太多
【发布时间】:2021-04-20 15:53:02
【问题描述】:

请看下面的代码 sn-p,它基本上只是将 1 字节左移 24 位。

uint64_t i = 0xFFFFFFFF00000000;
printf("before: %016llX \n", i);
i += 0xFF << 24;
printf("after : %016llX \n", i);

// gives:
// before: FFFFFFFF00000000
// after : FFFFFFFEFF000000

最重要的 32 位是 FFFFFFFE(注意最后的 E)。这不像我预期的那样。我不明白为什么将 1 个字节左移 24 位会触及第 32 位(第 31 位应该是最后一个修改的)它将最后一个 F (1111) 更改为 E (1110)) .

为了使其正常工作,我使用了0xFF unsigned (0xFFU)。

uint64_t i = 0xFFFFFFFF00000000;
printf("before: %016llX \n", i);
i += 0xFFU << 24;
printf("after : %016llX \n", i);

// gives:
// before: FFFFFFFF00000000
// after : FFFFFFFFFF000000

为什么有符号整数 (0xFF) 的位移位触摸/重置太多了?

【问题讨论】:

标签: c bit-shift unsigned


【解决方案1】:

你左移到符号位。

整数常量0xFF 的类型为int。假设 int 是 32 位,则表达式 0xFF &lt;&lt; 24 将设置为 1 的位移动到有符号整数触发 undefined behavior 的高位,在您的情况下表现为意外值。

这在C standard 的第 6.5.7p4 节中有详细说明:

E1 &lt;&lt; E2 的结果是E1 左移E2 位位置;空出的位用零填充。如果E1 具有无符号类型,则结果的值为 E1×2E2,以比结果类型中可表示的最大值多一个模数减少。如果E1 具有带符号类型和非负值,并且 E1×2E2 在结果类型中是可表示的,那么这就是结果值;否则,行为未定义。

通过使用U 后缀,这使得常量具有unsigned int 类型,并且由于没有符号位,所以将设置为 1 的位移到高位是有效的。

【讨论】:

  • 我认为这是实现定义的行为?
  • @EugeneSh。根据 6.5.7p4 未定义。右移一个负值是实现定义的。
  • 啊,我的错。我曾经相信我的记忆曾经:)
  • @dbush Uah ...完美的答案。这说明了一切。非常感谢!
  • @dbush 假设0xFF 将是unsigned char 而不是unsigned int,6.5.7p4 是否也适用?所以将上面的0xFF 替换为c,定义为unsigned char c = 0xFF。这不起作用,尽管它没有签名。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 2011-03-09
  • 2015-04-06
  • 1970-01-01
相关资源
最近更新 更多