位运算:进行而进制为的运算
系统软件常常要处理而进制的问题。
eg:将一个存储单元中的各二进制位左移或者右移一位,两个数按位相加等等。
云算符 含义
& 按位与
| 按位或
^ 按位异或
~ 取反
<< 左移
>> 右移
运算量只能够是整型或字符型的数据,不能够为实型数据。
1)按位与
同则不变,异则为0 ;
eg:
011
(&)101
—————————
001
即为:
3&5=1;
用途:
(1)清零
eg:要将一个单元清零,即使其全部而进制为0,只要找一个二进制数,其中各个位符合以下条件:原来的数中的1的位,相对应的位为0.然后使二者进行&运算,即可达到清零的目的。
eg:
00010101
(&) 11101010
___________________
00000000
(2)取一个数中的某些指定位。
eg:有个整数a(2个字节),想要起其中的低字节,只需要将a与(377)8 进行按位与。
(377)后面的8个位都是1,前面的高字节的位都是0,相与了之后,只保留了低字节的数据。
(3)想要保留哪一个位置的数据,就要在哪一个位置上的数进行&运算,次数在该位取1。
就是上面(2)中的一般性。
2)“按位或”运算符(|)
就是而进制为上主要有一个是“1”,结果在该位位上就是 1 的结果。
作用就是:具有保留“1”的作用。
3)“异或”运算符(^)——————————> 判断两个位置上是否为“异”,为“异”就去1,否则为0;
同则为0,异则为1.
应用:
(1)是特定的位翻转
与所有位上的数都是1 的进行异或的时候,该位上的数据将会翻转;0——>1; 1——>0 ;
(2)与0相^,保留原值。
(3)交换两个值,不用临时变量
eg:
a=3,b=4;
将a、b的值进行交换,可以实现如下:
a = a^b;
b = b^a;
a = a^b;
原理:
a = a^b;
a= 011
(^) b= 100
————————————
a= 111 = 7
(^) b= 100 b= b^a;
————————————
b= 011 = 3
(^) a= 111
————————————
a= 100 =4
可以实现了转换
4)“取反”运算符
单目运算符,用来对而进制数按位取反,即为将0变为1,1变为0.
~025是对8进制的25按位求反。 取反之后为:177752
5)左移运算符(<<)
将一个数的二进制位全部左移若干位
eg: a = a<<2; 将a的二进制数左移2位,右补0.
a = 15,二进制为:00001111,左移两位得:00111100,十进制为:60
(高位左移后,溢出将会舍弃)
左移一位相当于该数*2,2位则为4
总结:左移n位,将会是原来的数乘以2^n;
6)右移运算符(>>)
a>>2 表示将a的各二进制右移2位,移到右端的低位被舍弃,对无符号的数,高位补0;
eg:a=017时,二进制为:00001111
a>>2 为:00000011 舍弃了后面的两位。
即为:右移n位,相当于除以2^n位。(无符号的)
有符号的
正数的时候:如果原来的符号为0(该整数位正),则左边也是移入0(和上面一样);
如果符号位原来是1(即为:负数),则左边移入0还是1,这个要取决于所用的计算机系统。
有的系统移入0,有的系统移入1. 移入0的称为“逻辑右移”;移入1的称为“算术右移”
7)位运算赋值运算符
位运算符 与 赋值运算符可以组合称为符合赋值运算符,
eg:&= 、|= 、>>= ,<<= ,^=
8)不同长度的数据进行位运算
若是两个数据的长度不同(eg:long型和int型)进行位运算的时候,系统将会将二者按右端对齐。如果b为正数,则左侧16位补满0,若b为负数,做左端的应该补满1,如果b为无符号整数型,则左侧添满0。
8)位段(对内存中得信息一般是以字节为存储单位)
实际上一个存储信息不必要用一个或者多个字节,例如:"真"或“假”用0 、1 表示即可。
计算机中用于过程控制、参数检测或者数据通讯领域时,控制信息往往只是占有一个字节中的一个或几个二进制位,常常一个字节中存放多个信息。
即为:一个字节的每一个位都是可以用来存放信息位的。
如何向一个字节中的一个或几个二进制位进行赋值和改变它的值呢?
方法(1)
人为的将一个整型变量data分为几个部分。
eg:a ,b,c,d 分别占2位,6位,4位,4位。如果想将c的值变为12(假设原来是0)
(1》》将数12左移4位,是1100右边起第4~7位
(2》》将data与“12<<4”进行“按位或”运算,既可以将c的值变为12.
如果原来的值不是0,则应该先使它为0.
下面方法:data &=0177417 (左边的0表示8进制)
(0177417)8的二进制表示为:1111111100001111,即使data的第4~7位为0.
记住上面的字比较麻烦:可以使用
~(15<<4) 这个运算出来就是上面的数字了,其他的很大的数据也是可以使用这个方法来实现的。
方法(2)
c语言中“允许在一个结构体中以位为单位来指定其成员所占内存长度”,这种以位为单位的“位段”或“位域”
。利用为段可以较少的位数存储数据。
eg:
struct packed_data{
unsigned a:2;
unsigned b:6;
unsigned c:4;
unsigned d:4;
int i;
}data;
其中a,b,c,d 分别占2位、6位、4位、4位,i位整型,共占用4个字节。
下面关于位段的定义和引用:
(1)位段成员的类型必须指定位unsigned或int类型
(2)若某一位段要从另一个字开始存放,可以一下定义:
unsigned a:1;
unsigend b:2; 一个单元存储
unsigned :0;
unsigned c:3; ;另一个单元存储
ps:本来adb是可以存放在一个存储单元中的,由于用了长度为0的位段,其作用使下一位段从下一个存储单元开始存放。
因此,现在只是将a,b存储在一个单元中,c另存放在下一个单元。
(3)一个位段必须存储在一个单元中,不可以跨越两个单元。(即为:当前的单元的空间不够用,就用下一个单元进行存储)
(4)可以定义无名位段
unsigned a:1;
unsigned :2;(该空间是无名位段,空间不用)
unsigned b:3;
unsigned c:4;
(5)位段的长度不能够大于存储单元的长度,也不能够定义位段数组。
(6)位段可以用整型格式符输出。
eg:printf("%d,%d,%d",data.a,data.b,data.c);
当然也是可以使用%u,%0,%x等等格式来定义的。
(7)位段可以在数值表达式中引用,它会被系统自动的转换为整型数。