2.2.6 移位表达式
移位表达式的形式是
移位表达式 << 加性表达式
移位表达式 >> 加性表达式
加性表达式
其中,<<
表示左移,>>
表示右移。
移位表达式的计算
移位表达式计算的值是将 <<
或 >>
左边的值按照右边的值进行移位操作的结果。例如:
42 << 2 // 值为 168
假设 int
是32位的,42
的二进制表示是 0000 0000 0000 0000 0000 0000 0010 1010
,左移两位后的二进制表示是 0000 0000 0000 0000 0000 0000 1010 1000
(用 0
补充移出来的位),转换为十进制就是 168
。
当结果不超过范围时,读者可以简单地认为左移 N
位就是乘以 2^N
。相对的,右移 N
位就是除以 2^N
(向下取整)。
如果左移的结果超过范围,例如:
42 << 30
42
的二进制表示是 0000 0000 0000 0000 0000 0000 0010 1010
,左移30位后的二进制表示是 1000 0000 0000 0000 0000 0000 0000 0000
(超出范围的位会被舍弃),最后这个结果转换为十进制就是 -2147483648
。
任何情况下,如果移位表达式的右操作数是负数,或者超过了左边值的位数,那么这个表达式的行为是未定义的。
类似于加性表达式,移位表达式会进行整数提升。例如:
true << 2 // 值为 4
'a' << 2 // 值为 388
对于 int
类型的负值,右移操作在左边补充的是 1
,而不是 0
。例如:
-42 >> 2 // 值为 -11
-42
的二进制表示是 1111 1111 1111 1111 1111 1111 1101 0110
,右移两位后的二进制表示是 1111 1111 1111 1111 1111 1111 1111 0101
,转换为十进制就是 -11
。显然,即使是负数,右移操作也是向下取整的除以 2^N
。需要注意,这里的除法是向下取整的,而非向零取整,即 -42 / (2 ^ 2) = -11 ... 3
。于是,容易观察到,如果右移时,右操作数的值是左边的位数,正数会变成 0
,而负数会变成 -1
。
移位强迫症
设计移位是因为在计算机中,移位操作是非常高效的。在一些情况下,移位操作可以取代乘法和除法,从而提高程序的性能。
然而,了解到这一点的程序员也会强迫自己一定要写出移位操作,这样的做法是不好的。现代编译器能够将整数乘除2的幂次方的操作优化为移位操作,所以不需要强迫自己写出移位操作。
程序员应当选择适合当前开发情况的代码,在功能开发期使用高可读性容易重构的代码,在维护优化期使用性能更高的代码。当然,我们最希望的事情是这两个目标能够并行不悖。