int a = 1 << 32;
int b = 1 << 31 << 1;
为什么a == 1? b是我预期的0。
答案 0 :(得分:23)
对于整数,所有的班次都是mod 32,对于long是mod 64。
如果是左手的提升类型 操作数是
int
,只有五个 右手的最低位 操作数用作移位 距离。就好像是右手 操作数受到一点点的影响 逻辑AND运算符&amp; (§15.22.1)with 掩码值0x1f。调动,转移 因此实际使用的距离 总是在0到31的范围内, 包容。如果是左手的提升类型 操作数是
long
,然后只有六个 右手的最低位 操作数用作移位 距离。就好像是右手 操作数受到一点点的影响 逻辑AND运算符&amp; (§15.22.1)with 掩码值0x3f。调动,转移 因此实际使用的距离 始终在0到63的范围内, 包容。
至于为什么语言是这样设计的 - 我不知道,但C#有相同的设计决定。以下是带注释的ECMA C#规范所说的内容:
C#故意保留 实现定义的行为 miinimum。只有当他们被接受时 强迫对性能的影响 统一的行为会过分 (比如某些浮点数 精度问题)。因此,大小 每种积分类型都是精确的 指定,字符集是 固定为Unicode。对于轮班操作,也是统一的 行为已指定。有可能 使用一个额外的 指令(&amp; 0x1F或&amp; 0x3F)即 现代只需要很小的成本 处理器,特别是因为它 不是参考记忆。与...不同 浮点运算, 转变行为的差异将是 如果留下一时兴起的戏剧性 处理器;而不是一个小的 精度差异,完全 不同的积分结果将是 产生的。
在做出这个决定的时候 研究了参考资料 不同处理器的数量 架构。几乎没有 转变行为的一致性 计数超出-32 .. + 32的范围 32位操作数,分别为 -64 .. + 64位64位操作数。
(然后列出一些例子。)
这对我来说似乎是一个完全合理的解释。一致性肯定是重要的,如果在某些系统上以高效的方式实现不同的一致行为,我认为这是一个合理的解决方案。
答案 1 :(得分:0)
处理器实现转换指令的方式有所不同。
例如,IIRC,ARM处理器(32位ISA)占用移位寄存器的最低有效字节。 (班次实际上并不是ARM上的独立指令)。
只要底层处理器有一种模糊的移位方式,就可以更容易地清除除最低有效位之外的所有位(通常是一条指令),而不是检查移位是否很大和分支(实际上在ARM上这只是典型的)添加一条指令,因为所有指令都是有条件的。)