问题描述
请看下面的代码片段,它基本上只是向左移动 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
) 的位移位会过多地触摸/重置一位?
解决方法
您左移到符号位。
整数常量 0xFF
的类型为 int
。假设 int
是 32 位,表达式 0xFF << 24
将设置为 1 的位移入有符号整数触发 undefined behavior 的高位,在您的情况下,它表现为意外值。
这在 C standard 的第 6.5.7p4 节中有详细说明:
E1 << E2
的结果是 E1
左移 E2
位位置;空出的位用零填充。如果 E1
具有无符号类型,则结果的值为 E1×2E2,比结果类型中可表示的最大值减少模 1。如果 E1
有符号类型和非负值,并且 E1×2E2 在结果类型中是可表示的,那么就是结果值;否则,行为未定义。
通过使用 U
后缀,这使得常量具有 unsigned int
类型,并且将设置为 1 的位移入高位是有效的,因为没有符号位。