赞
踩
概念
右移运算符是将一个二进制数按指定移动的位数向右移动。
移动过程中,正数最高位补0,负数最高位补1,无符号数最高位补0。
补码
在计算机系统中,数值一律用补码来表示和存储,其中最高位表示符号位,1表示负数,0表示正数。
补码计算示例
以计算十进制-100的补码为例,计算过程为:
-100的原码:10000000 00000000 00000000 01100100
符号位保持不变,取反:11111111 11111111 11111111 10011011
加1后,-100补码为:11111111 11111111 11111111 10011100
右移运算
下面右移都是以整数为例,不考虑小数情况。
正数右移
正数右移高位需补0,以100右移4位为例:
操作 二进制 对应十进制
补码 00000000 00000000 00000000 01100100 100
右移4位 00000000 00000000 00000000 00000110 6
源码 00000000 00000000 00000000 00000110 6
最后可得: 100 >> 4 = 6
正数的右移相当于除法,右移几位就除以2的几次方,如100>>4 等效 100/2^4
负数右移
负数右移高位需补1,以-100右移4位为例:
操作 二进制 对应十进制
原码 10000000 00000000 00000000 01100100 -100
转换为补码 11111111 11111111 11111111 10011100 -100
右移4位,高位补1 11111111 11111111 11111111 11111001
保留符号位,按位取反 10000000 00000000 00000000 00000110
加1后转为源码 10000000 00000000 00000000 00000111 -7
最后可得: -100 >> 4 = -7
负数的右移不等于除法,即负数右移不能按除以2的n次方计算(n表示移动位数)。
无符号右移
无符号右移和正数右移相同,都是高位补0,以-100右移4位为例:
操作 二进制 对应十进制
原码 10000000 00000000 00000000 01100100 -100
转换为补码 11111111 11111111 11111111 10011100 -100
右移4位,高位补0 00001111 11111111 11111111 11111001
转为原码 00001111 11111111 11111111 11111001 268435449
最后可得: -100 >>> 4 = 268435449
右移28位后,最高位为0表示正数,所以原码即为补码本身。
“>>>”是Java里的无符号右移操作符。
总结
**
**
1、位操作符
(1)位与& 逻辑与&& 1&1=1 1&0=0 0&0=0 0&1=0
(2)位或 | 逻辑或 || 1 | 1=1 1 | 0=1 0 | 0=0 0 | 1=1
(3)位取反~ 逻辑取反 !
(4)位异或 ^ 不同为1,相同为0 1^1=0 1^0=1 0^0=0 0^1=1
总结:
位操作是按照二进制数的每一位进行操作的,逻辑操作是对数的整体操作的。
位与,与1位与无变化,与0位与为0。
位或,与1位或为1,与0位或无变化。
位异或,与1位异或会取反,与0位异或无变化。
(5)移位操作
C语言的移位要取决于数据类型
左移位 << 右移位 >>
无符号数, 逻辑移位
左移位时右侧补0
右移位时左侧补0
有符号数, 算数移位
左移位时右侧补0(相当于逻辑移位)
右移位时左侧补符号位,如果是正数就补0,负数就补1(第一位为符号位,0为正,1为负)
2、位操作符在操作寄存器时的特殊作用
(1)寄存器的操作要求
(2)改相应位的操作
基本思路:寄存器特定位改变而不影响其他位,构造合适的1和0组成的数和这个寄存器原来的值位与、位或、位取反
特定位清零用 & (用0清零)
特定位置1用 | (用1置1)
特定位取反用^ (用1取反)
代码举例
unsigned int a = 0xa12aaaa7;
unsigned int b = 0xFFFF00FF;
unsigned int c;
c = a & b;
// 16进制数的打印
printf("a & b = %#X.\n", c);
printf("a & b = 0x%x.\n", c);
3、使用位运算构建特殊二进制数
(1)使用位移获取特定位为1的二进制数
获取bit3-bit7为1,同时bit23-bit25为1,其余都为0的数
(2)使用位移获取特定位为0的二进制数
获取bit4-bit10为0,其余都为1的数
(3)总结
4、位运算的操作实战
回顾:清零用&,置1用 | ,取反用^
~和<< >>用来构建特定二进制数
unsigned int a ; // 定义无符号数,如果是有符号数,那么位移就会出问题
(1)给定一个整型数a,设置a的bit3,保证其他位不变
a |= (0x1<<3)
(2)给定一个整型数a,设置a的bit3-bit7,保证其他位不变
a |= (0x1F<<3) a |= (0b11111<<3)
(3)给定一个整型数a,清除a的bit15,保证其他位不变
a &= (~(0x1<<15)) a = (a | (0x7FFF<<0) | (a | (0xFFFF<<16) (不采用)
(4)给定一个整型数a,清除a的bit15-bit23,保证其他位不变
a &= (~(0x1FF<<15))
(5)给定一个整型数a,取出a的bit3-bit8
先将a的bit3-bit8不变,其余位清零
a &= (0x3F<<3)
再将a右移3位
a >>= 3
(6)给寄存器的bit7-bit17赋值937,其余位不受影响
先将bit7-bit17全部清零,其他位不变
a &= (~(0x7FF<<7))
再将937写入bit7-bit17,其他位不变
a |= (937<<7)
(7)将寄存器bit7-bit17中的值加17,其余位不受影响
先读出bit7-bit17的值
temp = a & (0x7FF<<7)
temp >>= 7;
给temp加17
temp += 17
将bit7-bit17清零
a &= (~(0x7FF<<7))
将temp算出的值写入到bit7-bit17
a |= (temp<<7)
(8)给寄存器bit7-bit17赋值937,同时给bit21-bit25赋值17
先将bit7-bit17和bit21-bit25清零,其他位不变
a &= (~ ( (0x7ff<<7) | (0x1f<<21) ) ) // 位或优先级高于~
再将937赋值到bit7-bit17,17赋值到bit21-bit25
a |= ((937<<7) | (17<<21))
printf(“a = %u.\n”, a); // %u 打印无符号数
5、技术升级:使用宏定义来完成运算
(1)直接用宏定义来置位、复位(最右边是第一位,bit0)
// 置位
#define SET_NTH_BIT(x, n) (x | ( (1U) << (n-1) ) )
// 复位
#define CLEAR_NTH_BIT(x, n) (x & ~ ( (1U) << (n-1) ) )
// 1后边的U表示这个数字是无符号数(有符号数的右移是会出问题的)
(2)将32位数x的第n位到第m位置位
// 关键点:我们需要一个算式来得到(m-n+1)个1的十六进制数
// 第1步,先得到32个1: ~0U (~按位取反得到32个1,如果直接1U那么就只有bit0位1)
// 第2步,将得到的数右移x位即可得到(m-n+1)个: (~0U) >> (32-(m-n+1)) 或 ~(~0U<<(m-n+1))
#define SET_BIT_N_M(x, n, m) (x | (((~0U) >> (32-(m-n+1))) << (n-1)))
#define SET_BIT_N_M(x, n, m) (x | ~(~0U<<(m-n+1))<<(n-1))
(3)截取变量的部分连续位(相当于4中的(5))
// 给定一个整型数a,取出a的bit3-bit8 // 先将a的bit3-bit8不变,其余位清零 a &= (0x3F<<3) // 再将a右移3位 a >>= 3 #define GETBITS(x, n, m) (x & ~(~0U << (m-n+1)) << (n-1)) >> (n-1)) // 思路: // 先将x的bit(n-1)-bit(m-1)不变,其余位清零 // 得到(m-n+1)个1的十六进制数 ~(~0U << (m-n+1)) (得到0x3F) // 将得到的16进制数左移(n-1) ~(~0U << (m-n+1)) << (n-1) (得到0x3F<<3) // x和左移后的数位与 x & ~(~0U << (m-n+1)) << (n-1) (a &= (0x3F<<3)) // 再将x右移(n-1)位 // 位与后的数右移(n-1) (x & ~(~0U << (m-n+1)) << (n-1)) >> (n-1) // 最终结果 #define GETBITS(x, n, m) (x & ~(~0U << (m-n+1)) << (n-1)) >> (n-1)) // 得到(m-n+1)个1的十六进制数的两种方式: // 32位的1先左移(m-n+1)位,那么低(m-n+1)位位0,高(32-(m-n+1))位为1,再将其按位取反, // 就得到低(m-n+1)位为1,高(32-(m-n+1))位为0。 ~(~0U << (m-n+1)) // 有(m-n+1)个1,那么就有32-(m-n+1)个0,将32位的1先右移32-(m-n+1), // 那么高32-(m-n+1)位为0,低(m-n+1)位为1。 (~0U) >> (32-(m-n+1))
下面的不要看了,哈哈哈。
**
1、基本操作符:“非”(¬)、“与”(^)、“或”(v)、“条件”(<->)、“双条件”(<->)。
“非”是一个一元操作符,只操作一项(¬p)。剩下是一元操作符,操作两项组成复杂语句(P^Q,PvQ,P->Q,P<->Q);
“与”(^)——>交集(∩);
“或”(v)——>并集(∪)。
2、逻辑运算符:与(&&)、或(||)、非(!)。
1、&&和||
&&:有0为0,同1出1。
||:
与:
或:
异或:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。