了解位移运算符

21

我无法理解这个移位运算符(c#参考):

class MainClass1
{
 static void Main()
    {
        int i = 1;
        long lg = 1;
        Console.WriteLine("0x{0:x}", i << 1);
        Console.WriteLine("0x{0:x}", i << 33);
        Console.WriteLine("0x{0:x}", lg << 33);
    }
}

/*
Output:
0x2
0x2
0x200000000
*/

class MainClass2
{
     static void Main()
     {
         int a = 1000;
         a <<= 4;
         Console.WriteLine(a);
     }
}

/*
Output:
16000
*/
4个回答

50

<< 是左移位运算符;它将一个值的二进制表示中的所有位向左移动“n”位(除了“mod”,请见“1”),并用0进行填充。

>> 是右移位运算符;它执行的几乎相反(向右移动),但对于有符号值(即可以为负数的值),它使用1进行填充负值,否则使用0进行填充。

1:

移位运算符本质上是数据宽度的“mod”。一个 int 是 32 位,所以在 Int32 中左移 33 (次)与左移 1 完全相同。你不会得到全部为 0 的结果。long 是 64 位,因此左移 33 给出不同的答案(原始值乘以 2^33)。

2:

每个左移(在数据宽度内)都等同于乘以 2(对于整数而言),因此 <<4 等同于 x2x2x2x2 = x16。

这是简单的二进制:

0000000001 = 1

<< goes to

0000000010 = 2
<< 转到
0000000100 = 4

<< goes to

0000001000 = 8

你好,我可以请你再解释一下吗?第一个问题中为什么我有0x200000000,第二个问题中为什么我有16000?非常感谢。 - Sara S
这就像是在说“为什么1 * 50000和1000 * 8不同” - 因为你正在做非常不同的事情。第一个是2^33(“幂”),第二个是1000 * 16。 - Marc Gravell
好的,我理解2^33和1000*16之间的区别了。我想知道为什么2^32。 - Sara S
33 是 int (2^5),现在想要转换为 long (2^6)。请问为什么是 2^33?谢谢。 - Sara S
1
1 << 1 = 2,即2的1次方;1 << 2 = 4,即2的2次方;1 << 33 = ... = 2的33次方(对于long类型;int类型不适用)。 - Marc Gravell
显示剩余4条评论

8

为了进一步解释Marc的回答(Marc,如果您愿意,请在您的回答中包含此部分,我会删除这个回答),这在规范的第7.8节中指定:


以下是预定义的移位运算符。

左移位:

  • int operator <<(int x, int count);
  • uint operator <<(uint x, int count);
  • long operator <<(long x, int count);
  • ulong operator <<(ulong x, int count);

<< 运算符将x向左移动由下面描述的位数。

x的超出x结果类型范围的高阶位将被丢弃,剩余位向左移动,并且低阶空位将设置为零。

右移位:

  • int operator >>(int x, int count);
  • uint operator >>(uint x, int count);
  • long operator >>(long x, int count);
  • ulong operator >>(ulong x, int count);

>> 运算符将x向右移动由下面描述的位数。

当x的类型为int或long时,x的低阶位将被丢弃,剩余位向右移动,并且如果x为非负,则高阶空位将设置为零,如果x为负,则设置为一。

当x的类型为uint或ulong时,x的低阶位将被丢弃,剩余位向右移动,并且高阶空位将设置为零。

对于预定义运算符,要移位的位数计算如下:

当x的类型为int或uint时,移位计数由count的低五位给出。换句话说,移位计数是从count & 0x1F计算得出的。

当x的类型为long或ulong时,移位计数由count的低六位给出。换句话说,移位计数是从count & 0x3F计算得出的。

如果结果移位计数为零,则移位运算符只返回x的值。



3

对于初学者程序员,以下是一些需要注意的事项:

为什么要使用移位运算符?它们似乎并没有什么作用。实际上,有两个原因:

  1. 它们非常快,因为几乎所有的CPU都有移位寄存器,这意味着移位操作是在硬件中完成的,所需的最小努力(周期)。

  2. 由于它们速度很快,很多协议和标准都被设计成充分利用这一点。例如IP地址操作、CRC检查、图形操作等。


0

移位运算符本质上是对数据宽度进行“模”运算。

胡说八道!如果移位量大于或等于数据宽度,则结果未定义。不要期望您所看到的相同“模”运算会在不同的编译器、同一程序中的不同移位情况或任何其他更改时发生,或者在同一编译器的不同版本中发生。这就是“未定义”的含义。


实际上,C# 4.0 语言规范指出: 1)当 x 的类型为 int 或 uint 时,移位计数由 count 的低五位给出。换句话说,移位计数是从 count & 0x1F 计算得出的。 2)当 x 的类型为 long 或 ulong 时,移位计数由 count 的低六位给出。换句话说,移位计数是从 count & 0x3F 计算得出的。 - user1143634

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接