我正在尝试使用C ++中的位数组数据结构。这是一种简单的好奇心,但我该如何解释:
uint64_t a = 1;
uint64_t b = a << 1;
cout << (a == (a << 64)) << endl; // get 1
cout << (a == (b << 63)) << endl; // get 0
似乎是&lt;&lt; x >= 64
时x为循环,x < 64
时以零填充。我错了吗?
如果没有,解释是什么?我认为64位整数不是自然周期性的。
答案 0 :(得分:5)
答案 1 :(得分:1)
正如YSC所解释的那样,在一个操作中移动超过类型大小的是未定义的行为;这个规则来自于将位移操作符直接映射到机器代码指令的愿望,这些指令在这种情况下具有不同的行为,这取决于处理器。
例如,在x86上,SHL指令屏蔽移位量为63(当在64位寄存器上操作时),这可能是您看到a<<64
保持为1的原因(64 & 63 == 0
因此,它实际上是一种无操作。
请注意,这只是一个教学解释,通常适用于简单情况(通常,禁用优化,或启用优化但移位量未知,因此当移位映射到底层平台移位操作码时)。当使用常量移动常量时,编译器可以传播值并以更高的精度在内部执行算术,或者,即使在一般情况下,也会发出在大于数据类型的寄存器中工作的代码并在最后截断(例如,它是合法的将uint32_t
的移位映射到完整的64位寄存器移位,虽然不是特别聪明),从而在这些不合规格的情况下给出不同的结果。请记住:未定义的行为是未定义的,您无法真正期待任何特定的事情发生。
另一方面,按两个步骤执行操作可以正常工作,因为两个操作都是明确定义的(它们在右边填充零,丢弃左边的位)。