16

这更像是一个语言设计而不是一个编程问题。

以下是JLS 15.19 Shift Operators的摘录:

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

如果左侧操作数的提升类型是long,则仅将右侧操作数的最低六位用作移位距离。

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

结果是以下情况为真:

(1 << 32) == 1

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

4

3 回答 3

8

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

因此,它们模仿硬件的功能。他们稍微修剪了一下,因为他们要求屏蔽,而 C 只允许它。尽管如此,Java 和 C# 仍然是“中级”语言。

于 2010-02-22T14:41:41.160 回答
5

因为在大多数编程环境中,整数只有 32 位。因此,5 位(足以表示 32 个值)已经足以移动整个整数。对于 64 位长度存在类似的推理:完全移位整个值所需的全部内容为 6 位。

我可以理解部分困惑:如果您的右手操作数是计算结果,其最终值大于 32,您可能希望它只是移动所有位而不是应用掩码。

于 2010-02-22T14:40:17.033 回答
5

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

相反,如果移位计数不在 0..31 范围内(对于 32 位 int),C/C++ 将移位指令的行为保留为未定义,允许任何行为。那是因为当 C 第一次实现时,不同的工具处理这些不同。例如,在 VAX 上,移动负数会移动另一个方向。因此,对于 C,编译器可以只使用硬件移位指令并执行它所做的任何事情。

于 2010-02-22T18:36:04.380 回答