像C#/ Java这样的高级语言掩盖位移计数操作数的原因是什么?

这更多的是语言设计而不是编程问题。

以下是JLS 15.19移位运算符的摘录:

如果左侧操作数的提升类型是int ,则只使用右侧操作数的五个最低位作为移位距离。

如果左侧操作数的提升类型很long ,则只使用右侧操作数的六个最低位作为移位距离。

这种行为也在C#中指定 ,虽然我不确定它是否在Javascript的官方规范中(如果有的话),但至少基于我自己的测试也是如此。

结果是以下情况属实:

 (1 << 32) == 1 

据我所知,这个规范很可能受到以下事实的启发:当移位32位值时(6位为64位),底层硬件仅占用计数操作数的5位,我可以理解在例如,JVM级别,但为什么高级语言(如C#和Java)会保留这种相当低级别的行为? 它们不应该提供超出硬件实现的更抽象的视图,并且行为更直观吗? (如果他们可以采取负数来表示向其他方向转移,那就更好了!)

Java和C#并非完全“高级”。 他们努力尝试将它们编译成有效的代码,以便在微基准测试中发挥作用。 这就是为什么它们具有诸如int的“值类型”而不是具有作为默认整数类型的真实整数,它们本身就是对象,并且不限于固定范围。

因此,它们模仿硬件的function。 他们修剪了一下,因为他们要求掩盖,而C只允许它。 Java和C#仍然是“中级”语言。

因为在大多数编程环境中,整数只有32位。 那么5位(足以表示32个值)已足以移动整个整数。 对于64位长的存在类似的推理:只需要6位就可以完全移动整个值。

我可以理解部分混淆:如果你的右手操作数是计算结果大于32的结果,你可能会期望它只是移位所有位而不是应用掩码。

C#和Java将移位定义为仅使用移位计数的低位,因为sparc和x86移位指令都是如此。 Java最初由Sun在sparc处理器上实现,而C#由Microsoft在x86上实现。

相反,如果移位计数不在0..31范围内(对于32位int),则C / C ++保留未定义移位指令的行为,允许任何行为。 那是因为当C首次实施时,不同的手工具有不同的处理方式。 例如,在VAX上,移动负量会改变另一个方向。 因此,使用C,编译器可以只使用硬件移位指令并执行任何操作。