为什么是
的结果uint32_t s = 64;
uint64_t val = 1ull << s;
和
uint64_t s = 64;
uint64_t val = 1ull << s;
1? 但是
uint64_t val = 1ull << 0x40;
优化到0? 我真的不明白为什么它等于1。无论我使用VC ++还是g ++编译器,都是如此。
当1ull << s
等于64时,如何确保s
等于0,我认为正确的结果是什么?我还需要imo。我程序中的结果正确。
答案 0 :(得分:2)
这是因为在x64上,指令SHL
(在64位源/目标操作数上操作时)仅使用移位量的低6位。实际上,您正在移动0位。
从“ SAL / SAR / SHL / SHR-Shift”条目下的“ Intel 64和IA-32体系结构软件开发人员手册”(可以从Intel下载PDF格式,很难链接到)。说明:
计数被屏蔽为5位(如果在64位模式下使用REX.W,则为6位)。计数范围限制为0到31(如果使用64位模式和REX.W,则为63)。
如下所述,在C ++语言中,将整数移位比其大小还多的位也是“未定义行为”。 (感谢@sgarizvi提供参考。)C ++标准在8.5.7节(移位运算符)下指出:
如果右操作数为负,或者大于或等于提升后的左操作数的位长度,则行为不确定。
这就是为什么编译器生成的代码在不同条件下(恒定或可变移位计数,是否优化等)产生不同结果的原因
关于如何“修复”它,我没有聪明的窍门。您可以执行以下操作:
template <typename IntT>
IntT ShiftLeft (IntT x, unsigned count) {
// Optional check; depends on how much you want to embrace C++!
static_assert(std::is_integral_v<IntT>, "This shift only works for integral types.");
if (count < sizeof(IntT) * 8)
return x << count;
else
return 0;
}
该代码适用于有符号和无符号整数类型(有符号和无符号值的左移相同)。