1.4 “取反”运算符(~)
~是一个单目(元)运算符,用来对一个二进制数按位取反,即将0变1,1变0。例如~025是对八进制数25(即二进制数00010101)按位求反。
0000000000010101
(~)
1111111111101010
即八进制数 177752。因此,~025的值为八进制数177752。不要以为~025的值是-025。下面举一例说明~运算符的应用。
若一个整数a为16位,想使最低一位为0,可以用
a=a &.0177776
177776 即二进制数11111111111110,如果a的值为八进制数75,a &0177776的运算可以表示如下:
0000000000111101
(&)1111111111111110
0000000000111100
a的最后一个二进位变成0。但如果将C源程序移植到以32位存放一个整数的计算机系统(如VAX 11/780)上,由于一个整数用4个字节(32位表示),想将最后一位变成0就不能用a&.0177776了。读者可以自己算一下,当a=017776543603时,a&.0177776的结果是什么?
为了适应以32位存放一个整数的计算机系统,应改用
a &.037777777776
这样改动使移植性差了,可以改用
a=a&~1
它对以16位和以32位存放一个整数的情况适用,不必作修改。因为在以2个字节存储一个整数时,1的二进制形式为0000000000000001,~1是11111111111110(注意~1不等于-1,弄清~运算符和负号运算符的不同)。在以4个字节存储一个整数时,~1是111111111111111111111111110。
~运算符的优先级别比算术运算符、关系运算符、逻辑运算符和其他位运算符都高,例如:~a&b,先进行~a运算,然后进行&运算。
1.5左移运算符(<<)
用来将一个数的各二进位全部左移若干位。例如:
a=a<<2
将a的二进制数左移2位,右补 0。若a=15,即二进制数00001111,左移2位得00111100,即十进制数60(为简单起见,我们用8位二进制数表示十进制数15,如果用16位,结果是一样的)。
高位左移后溢出,舍弃不起作用。
左移1位相当于该数乘以2,左移2位相当于该数乘以22=4。上面举的例子15<<2=60,即乘了4。但此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况。例如,假设以一个字节(8位)存一个整数,若a为无符号整型变量,则a=64时,左移一位时溢出的是0,而左移2位时,溢出的高位中包含1。
由表 12.2可以看出,若a的值为64,在左移1位后相当于乘2,左移2位后,值等于0。左移比乘法运算快得多,有些C编译程序自动将乘2的运算用左移一位来实现,将乘2"的幂运算处理为左移n位。
1.6 右移运算符(>>)
a>>2 表示将a的各二进位右移2位。移到右端的低位被舍弃,对无符号数,高位补 0。如a=017 时:
a为 00001111, a >> 2为00000011 11
此二位舍弃
右移一位相当于除以2,右移n位相当于除以2”。
在右移时,需要注意符号位问题。对无符号数,右移时左边高位移入0。对于有符号的值,如果原来符号位为0(该数为正),则左边也是移入0,如同上例表示的那样。如果符号位原来为1(即负数),则左边移人0还是1,要取决于所用的计算机系统。有的系统移入
o,有的移人1。移人0的称为“逻辑右移”,即简单右移。移人1的称为“算术右移”。例如, a的值为八进制数113755。
a: 1001011111101101
a>>1:0100101111110110(逻辑右移时)
a>>1:1100101111110110(算术右移时)
在有些系统上,a>>1得八进制数045766,而在另一些系统上可能得到的是145766。 TurboC和其他一些C编译采用的是算术右移,即对有符号数右移时,如果符号位原来为1,左面移人高位的是1。
1.7 位运算赋值运算符
位运算符与赋值运算符可以组成复合赋值运算符
如:&=,|=,>>=,<<=,∧=
例如,a&=b相当于a = a &b,a << =2相当于a =a<<2。
1.8不同长度的数据进行位运算
如果两个数据长度不同(例如long型和int型)进行位运算时(如a&b,而a为 long型,b为int型),系统会将二者按右端对齐。如果b为正数,则左侧16位补满0。若b为负数,左端应补满1。如果b为无符号整数型,则左侧添满0。