一、位运算符和位运算
1.基本概念
位运算是指按二进制位进行的运算,这是因为在系统软件中,常要处理二进制位的问题。
例如,将一个存储单元中的各二进制位左移或右移一位,两个数按位相加等。
C语言提供位运算的功能,与其他高级语言(如PASCAL)相比,具有很大的优越性。
2.位运算符
常见位运算符及含义如下:
位运算符中除~以外,均为二目(元)运算符,即要求两侧各有一个运算量;
运算量只能是整型或字符型的数据,不能为实型数据。
按位与运算符&
含义:
参加运算的两个数据,按二进制位进行与运算。
如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。
例如:
0 & 0 = 0, 0 & 1 = 0, 1 & 0 = 0, 1 & 1 = 1
3 & 5
并不等于8,而是二进制按位与运算,如下:
如果参加&运算的是负数(如-3&-5),则要以补码形式表示为二进制数,然后再按位进行与运算。
按位与运算的用途:
(1)清零
若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合以下条件:
原来的数中为1的位,新数中相应位为0。
然后使二者进行&运算,即可达到清零目的。
例如,要将二进制数11100101的第2位清零,则可以另找一个数11100001,两者进行与运算即可。
(2)取一个数中某些指定位
例如:我们需要对一个字型数据取出其低8位的值时,我们可以如下:
按位或操作符|
两个相应的二进制位中只要有一个为1,该位的结果值为1。
即:
0 | 0 = 0, 0 | 1 = 1, 1 | 0 = 1, 1 | 1 = 1
例如:
练习:
编写一个小程序,将输入的大写字母转换为小写字母,输入的小写字母转换为大写字母,要求用位操作完成转换过程。
实现思路:
对于一个大写字母和对应的小写字母的二进制形式,只是第5位不同,小写字母为1,大写字母为0。
代码如下:
#include <stdio.h> int main(){ char ch, temp; printf("Please input a character:\n"); ch = getchar(); temp = getchar(); while(!(ch >= 'A' && ch <= 'z') || (ch > 'Z' && ch <'a')){ printf("Input Error, please input again:\n"); ch = getchar(); } if(ch & 32){ ch &= 223; } else{ ch |= 32; } putchar(ch); ch = getchar(); putchar(ch); return 0; }
打印:
Please input a character: 3 Input Error, please input again: a A
异或运算符^
异或运算符^也称XOR运算符。
它的规则是:
若参加运算的两个二进制位同号则结果为0(假),异号则结果为1(真)。
即:
0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0
例如:
异或运算符应用:
(1)使特定位翻转
设有01111010,想使其低44位翻转,即1变为0,0变为1,可以将它与00001111进行^运算,即:
(2)与0相^,保留原值
例如:
因为原数中的1与0进行^运算得1,0^0得0,故保留原数。
(3)交换两个值,不用临时变量
例如a = 3, b = 4
,现在想将a、b变量的值交换位置,传统的做法是多定义一个temp变量,现在使用位运算也可以达到同样的目的:
a = a ^ b; b = b ^ a; a = a ^ b;
这是因为异或运算符可以进行逆运算,这种方法也常应用于加密算法。
取反运算符~
~是一个单目(元)运算符,用来对一个二进制数按位取反,即将0变1,将1变0。
例如,~025是对八进制数25(即二进制数00010101)按位求反。
例如:
左移运算符<<
左移运算符是用来将一个数的各二进制位全部左移若干位。
例如,a = a << 2表示将a的二进制数左移2位,右边补0。
若a = 15,即二进制数00001111,左移2位得00111100(十进制数60);
若高位左移后溢出,舍弃。
左移1位相当于该数乘以2,左移2位相当于该数乘以4,15 << 2 = 60,即乘了4。
但此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况。
假设以一个字节(8位)存一个整数,若a为无符号整型变量,则a=64时,左移一位时溢出的是0,而左移2位时,溢出的高位中包含1。