内容正文:
第12章 位运算
第12章 位运算
2
有从0到7编号的八盏灯,怎样在程序中模拟控制它们的开关呢?
可以定义一个无符号的字符型变量c,用其存储状态中的一位对应于一盏灯。当某位上的数为1时,表示对应的灯亮;为0时表示对应的灯灭。
如变量c的值为128(1000 0000),则只有7号灯亮,其余的灯灭;为192时(1100 0000),6号和7号灯亮,其余的灭。
通过调整变量c的值来模拟开关灯的操作?
这样做虽然节约了存储空间,但怎样通过某位状态的变化来控制一盏灯的“开关”却是个问题。“如果0号灯亮就关掉它;否则,就打开它”,怎样通过调整变量c的值来完成这个操作呢?
与0号灯状态对应的是变量c存储状态最低位上的数,根据要求,如果变量c存储状态最低位上的数是1,就将其变为0;否则,即最低位上数是0,就将其变为1。
12.1.1 按位与操作符&
按位与操作符&将参与运算的两个操作数以二进制位为单位进行“与”运算。与运算时,如果两个二进制位上的数均为1,则运算结果的此位为1;否则,运算结果的此位为0。
例如:char a = -2, b = 3,则a & b的值为2。
按位与操作符&的特点
由按位与操作符&的运算规则可知,0与1进行按位与操作,结果为0;1与1进行按位与操作,结果为1,因此,与1进行按位与操作时,操作数是几结果还是几。
与0进行按位与操作时,无论操作数是0还是1,结果总是0。
利用按位与操作符&可以在不影响其它位的情况下将整数的某位设置为0。
按位与操作符&的特点
设无符号字符型c的值为165(1010 0101),即现在是第0、2、5、7号灯亮,需熄灭7号灯时,只要让c与0x7f(0111 1111)进行按位与运算即可。c = c & 0x7f
按位或操作符|
按位或操作符|将参与运算的两个操作数以二进制位为单位进行“或”运算。或运算时,如果两个二进制位上的数都为0,则运算结果的此位为0;否则,此位为1。
由运算规则可知,利用按位或操作符|可以在不影响其它位的情况下将一个整数的某位设置为1。
设无符号字符型c的值为165,需打开1号灯时,只要让c与0x2进行按位或运算即可。c |= 0x2
12.1.3 异或操作符^
异或操作符^也称xor操作符。异或操作符^将参与运算的两个操作数以二进制位为单位进行“异或”运算。
“异或”运算可理解为“判断是否不同(为异)”的运算。异或运算时,如果两个二进制位上的数相同,则运算结果的此位为0(表示否,不为异);如果两个二进制位上的数不同,则运算结果的此位为1(表示是,为异)。
异或操作符^的特点
分析运算规则可知,某位与1进行异或运算时,结果与该位正好相反(翻转),即原来是1时结果为0,原来是0时结果为1;某位与0进行异或时,结果与该位相同。
设无符号字符型c的值为165,需要改变0号到3号灯的状态(即亮的灭,灭的亮)时,只要让c与0xf进行异或运算即可。c ^= 0xf
取反操作符~
取反操作符~是一个单目操作符,用来对一个整数按二进制位取反。按位取反时,原来是1的结果为0,原来是0的结果为1。
设无符号字符型c的值为165,需要改变所有灯的状态时,只要进行取反运算即可,即c = ~c。
~a等价于-1-a,故~a+1的值为-1-a+1,即-a。
12.1.5 左移操作符<<
左移操作符<<的常用形式为:a << n
其中,a和n均为整数,求值时a的二进制位全部左移n位,右端补n个0,舍弃左端移出的n位。显然n的取值范围通常为1至sizeof(a) * 8。
在位运算中,左移操作符常用于构造操作数。
无符号字符型变量c的值为165,需点亮第6号灯,可以用如下表达式c |= 1 << 6模拟,其中,1 << 6即0100 0000。
左移操作符<<
左移操作也可看作算术运算,a左移1位的值为a的2倍,左移2位的值为a的4倍,……。计算a<<1要比计算a*2快得多。
左移操作符的优先级低于算术操作符但高于关系操作符。单目操作符~的优先级较高。按位与、按位或和按位异或的优先级低于关系操作符,但高于逻辑操作符。
12.1.6 右移操作符>>
右移操作符与左移操作符类似,表达式a >> n求值时,会将a的二进制位全部右移n位,右端移出的n位被舍弃。根据左端移入数的不同,右移操作分为“逻辑右移”和“算术右移”两种。
逻辑右移时,无论a为何类型,左端均移入n个0;
算术右移时,如果a为非负数,则左端移入n个0;如果a为负数,则左端移入n个1。C语言编译器多采用算术右移。
例12-1 分析下面求整数绝对值的函数
如果x>=0,则y的值为0,(x ^ y) - y 的结果仍为x。
如果x<0,则y的值为-1,
x与-1进行异或运算实际
上是对x进行取反操作,
再减y就是再加1,也