位运算 学习

首先介绍逻辑运算中的真值表,如表

A

B

A与B

A或B

非A

A异或B

 

0

0

0

0

1

0

 

0

1

0

1

1

1

 

1

0

0

1

0

1

 

1

1

1

1

0

0

 

其中
0 代表错误(伪)
1 代表正确(真)
为了实现对应的逻辑运算,在C语言中提供对应的位逻辑运算符:
& 位与运算
| 位或运算
^ 位异或
~ 位非
另外,C语言中提供位移运算符。
<< 位左移
>> 位右移

位与运算:

位与运算的主要用途如下:

(1)清零:快速对某一段数据单元的数据清零,即将其全部的二进制位为0。例如整型数a=321对其全部数据清零的操作为a=a&0x0。

(2)获取一个数据的指定位。例如获得整型数a=的低八位数据的操作为a=a&0xFF。

 

321=

0000 0001 0100 0001

&

0xFF =

0000 0000 1111 11111

=

 

0000 0000 0100 0001

获得整型数a=的高八位数据的操作为a=a&0xFF00。
==
a&0XFF00==

 

321=

0000 0001 0100 0001

&

0XFF00=

1111 1111 0000 0000

=

 

0000 0001 0000 0000

(3)保留数据区的特定位。例如获得整型数a=的第7-8位(从0开始)位的数据操作为:

110000000

 

321=

0000 0001 0100 0001

&

384=

0000 0001 1000 0000

=

 

0000 0001 0000 0000

位或运算

位或运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑或运算。例如:int型常量5和7进行位或运算的表达式为5|7,结果如下:

 

5=

0000 0000 0000 0101

|

7=

0000 0000 0000 0111

=

 

0000 0000 0000 0111

位或运算的主要用途如下。
设定一个数据的指定位。例如整型数a=321,将其低八位数据置为1的操作为a=a|0XFF

 

321=

0000 0001 0100 0001

|

 

0000 0000 1111 1111

=

 

0000 0000 1111 1111

提示 注意逻辑运算符||与位或运算符|的区别


位异或运算

位异或运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑异或运算。只有当对应位的二进制数互斥的时候,对应位的结果才为真。
例如:int型常量5和7进行位异或运算的表达式为5^7,结果如下:

 

5=

0000 0000 0000 0101

^

7=

0000 0000 0000 0111

=

 

0000 0000 0000 0010

位异或运算的主要用途:

  1. 定位翻转:设定一个数据的指定位,将1换为0,0换为1。例如整型数a=321,,将其低八位数据进行翻位的操作为a=a^0XFF;

(a)10=(321)10=(0000 0001 0100 0001)2
a^0XFF=(0000 0001 1011 1110)2=(0x1BE)16

 

321=

0000 0001 0100 0001

^

0xFF=

0000 0000 1111 1111

=

 

0000 0001 1011 1110

  1. 数值交换。例如a=3,b=4。在例11-1中,无须引入第三个变量,利用位运算即可实现数据交换。

例12-1 编程实现两个数据的交换。

#include "stdafx.h"
int main(int argc, char* argv[])
{
int a,b;
a=3,b=4;
printf("\na=%d,b=%d",a,b);
a=a^b;
b=b^a;
a=a^b;
printf("\na=%d,b=%d",a,b);
return 0;
}
程序的运行结果为
a=3,b=4
a=4,b=3
分析程序的运算过程如下:
b=b^(a^b)=b^b^a=a;
a=a^b=(a^b)^(b^a^b)=a^b^b^a^b= a^a^ b^b ^b=b


位非运算

位非运算的实质是将参与运算的两个数据,按对应的二进制数逐位进行逻辑非运算。例如:对int型常量7进行位非运算的表达式为~7,结果为2,计算过程如下:

~

7=

0000 0000 0000 0111

=

 

0000 0000 0000 0010


左移运算符

左移运算的实质是将对应的数据的二进制值逐位左移若干位,并在空出的位置上填0,最高位溢出并舍弃。例如
int a,b;
a=5;
b=a<<2;
则b=20,分析过程如下:
(a)10=(5)10=(0000 0000 0000 0101)2
b=a<<2;
b=(0000 0000 0001 0100)2=(20)10
从上例可以的知b/a=4=22,可以看出位运算可以实现二倍乘运算。由于位移操作的运算速度比乘法的运算速度高很多。因此在处理数据的乘法运算的时,采用位移运算可以获得较快的速度。
提示 将所有对2的乘法运算转换为位移运算,可提高程序的运行效率


右移运算符

右移运算的实质是将对应的数据的二进制值逐位右移若干位,并舍弃出界的数字。如果当前的数为无符号数,高位补零。例如:
int (a)10=(5)10=(0000 0000 0000 0101)2
b=a>>2;
b=(0000 0000 0000 0001)2=(1)10
如果当前的数据为有符号数,在进行右移的时候,根据符号位决定左边补0还是补1。如果符号位为0,则左边补0;但是如果符号位为1,则根据不同的计算机系统,可能有不同的处理方式。
可以看出位右移运算,可以实现对除数为2的整除运算。
提示 将所有对2的整除运算转换为位移运算,可提高程序的运行效率


其他位运算符

在C语言中还提供复合的位运算符,如下:
&=、!=、>>=、<<=和^=
例如:a&=0x11等价于 a= a&0x11,其他运算符以此类推。
不同类型的整数数据在进行混合类型的位运算时,按右端对齐原则进行处理,按数据长度大的数据进行处理,将数据长度小的数据左端补0或1。例如char a与int b进行位运算的时候,按int 进行处理,char a转化为整型数据,并在左端补0。补位原则如下:
1) 对于有符号数据:如果a为正整数,则左端补0,如果a 为负数,则左端补1。
2) 对于无符号数据:在左端补0。
例11-2 获得一个无符号数据从第p位开始的n位二进制数据。假设数据右端对齐,第0位二进制数在数据的最右端,获得的结果要求右对齐。

#include <stdio.h>
/*getbits:获得从第p位开始的n位二进制数 */
unsigned int getbits(unsigned int x, unsigned int p, unsigned n)
{
unsigned int a;
unsigned int b;
a=x>>(p+1);
b=~(~0<<n);
return a&b;
}
void main()
{
unsigned int a=123;
unsigned int b;
b=getbits(a,2,4);
printf("a=%u\t b=%u\n",a,b);
printf("a=%x\t b=%x\n",a,b);
}
程序运行结果为
a=123 b=15
a=7b b=f
解释如下:a 的二进制形式如下:
0000 0000 0111 1011
左移p+1位(从0开始)
0000 0000 0000 1111
0的二进制形式如下:
0000 0000 0000 0000
0取反
1111 1111 1111 1111
0右移4位(从0开始)
1111 1111 1111 0000
0右移4位取反,因此b的二进制形式为
0000 0000 0000 1111
a&b的结果如下
0000 0000 0000 1111
提示 在某一平台进行程序开发时,首先要求了解此系统的基本数据类型的有效范围, 对涉及的位运算进行评估,特别是要对边界数据进行检测,确保计算正确。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值