3.7.6 移位运算符
移位运算符也是对位的操纵。左移位运算符(<<)引起运算符左边的操作数向左移动,移动位数由运算符后面的操作数指定。右移位运算符(>>)引起运算符左边的操作数向右移动,移动位数由运算符后面的操作数指定。如果移位运算符后面的值比运算符左边的操作数的位数大,则结果是不定的。如果左边的操作数是无符号的,右移是逻辑移位,所以最高位补零。如果左边的操作数是有符号的,右移可能是也可能不是逻辑移位(也就是说,行为是不定的)。
移位可以和等号结合(<<=或>>=)。左值由左值按右值移位后的结果代替。
下面是一个例子,说明所有涉及位运算的运算符的使用。首先,这里单独创建了一个通用的函数,用二进制格式打印一个字节,所以这个函数很容易被重用。头文件声明了这个函数:
下面是这个函数的实现:
函数printBinary()取出一个字节并一位一位地显示出来。表达式
在每一个相继位的位置产生一个1,例如:00000001,00000010,等等。如果这一位和变量val按位与并且结果不是零,就表明val的这一位为1。
最后,在例子中使用下面的函数显示位操作运算符:
再一次使用预处理宏节省输入。它打印你选择的字符串,然后是一个表达式的二进制表示形式,再后是换行。
在main()中,变量都是unsigned的。这是因为一般来说,在使用字节进行工作时并不希望用带符号数。对于变量getval而言,可能要使用int来替代char,因为语句“cin>>”以另一种方式把第一个数字看做是一个字符。通过把getval赋值给a和b,该值被转换为一个单独的字节(通过对它截尾)。
“<<”和“>>”实现位的移位功能,但是当移位越出数的一端时,那些位就会丢失(这就是通常所说的,那些位掉进了神秘的位桶(bit bucket)中,丢弃在这个桶中的位有可能需要重用)。操作位的时候,也可以执行旋转(rotation),即在一端移掉的位插入到另一端,好像它们在绕着一个回路旋转。尽管大多数计算机处理器提供了机器级的旋转命令(所以我们会在这种处理器的汇编语言中看到它),但在C和C++中,不直接支持旋转。大概C的设计者认为对“旋转”的处理应该适可而止(正如他们说的那样,他们的目标是建立最小的语言),因此我们可以建立自己的旋转命令。例如下面是实现左旋和右旋的函数:
试着在程序Bitwise.cpp中使用这些函数。注意,在使用这些函数前编译器必须在Bitwise.cpp中看到rol()和ror()的定义(或者至少是声明)。
通常情况下,使用位函数的效率非常高,因为它们被直接翻译成汇编语言语句。有时一个单独的C或C++语句会产生一行单独的汇编代码。