布尔代数以及C语言上的位运算
布尔代数是一个数学知识体系,它在0和1的二进制上演化而来.
我们不需要去彻底了解这个知识体系,但是里面定义了集中二进制的运算,却是我们在平时的编程过程中也会遇到的.这四种运算分别是或,与,非,异或.下图展示了布尔代数的知识体系,对这四种运算的定义:
从左到右依次是非,与,或,异或.这个图阐述的是针对一位二进制的运算结果,我们可以将其扩大到N位二进制.比如两个二进制[aw,aw-1...a1]和[bw,bw-1...b1],它们的四种运算则是对两者每一个相对应的位上做相应的运算。
也就是说,倘若假设结果是[cw,cw-1...c1]的话,那么对于任意ci都满足ci = ai (|,&,^) bi,如果是对[aw,aw-1...a1]进行非运算的话,那么ci = ~ai。
C语言上的位运算
在C语言中,也支持位运算,而他的计算方式就是布尔代数中的位运算.位运算我们最常使用的是掩码的方式.比如我们知道一个整数x,如果我们想取得这个整数得最后一个字节的整数值的话,就可以采用位运算.就像下面这样
#include <stdio.h>
int main(){
unsigned int i = 0x12345678;
unsigned int j = 0xFF;
unsigned int k = i & j;
printf("%X\n",k);
}
最终我们得到的结果是78,也就是整数i的最后一个字节的值,我们使用掩码0xFF以及与运算符过略掉整数i的高位的三个字节.
C语言的逻辑运算
C语言的逻辑运算有||,&&和!,这比较容易与刚才的|,&和~搞混.逻辑运算符比较特别,在这种运算的结果中认为所有非0的数值都是true,而为0的则为false.案例如下:
#include <stdio.h>
int main(){
unsigned int x = 0x12345678;
unsigned int i = !x;
unsigned int j = ~x;
unsigned int m = !!x;
unsigned int n = ~~x;
printf("%u %u\n",i,j);
printf("%u %u\n",m,n);
}
从这个程序的结果可以很容易的看出!和~运算的结果,输出如下:
0 3989547399
1 305419896
结果很明显,左边是!x以及!!x的结果,只有0和1,而右边的则是~x和~~x的结果.这里可以很明显的看出逻辑非与位的非运算的区别.前置只有0和1,而后者则是针对每一位二进制取反.
除了结果上的区别之外,它们二者还有一个区别,就是逻辑运算倘若可以根据第一个表达式确定结果的话,那么将不会计算第二个表达式.撅个简单的例子,假设有两个表达式a和b,对于a&&b,倘若a为a假,则不会计算b表达式的值.但是对于a&b则不痛,无论a表达式的值为何,都要计算b表达式的值.
C语言的移位运算
移位运算分为两种,左移(<<)和右移(>>).
举个例子吧,这个不好说
设无符号短整型变量a为0111(对应二进制数为0000000001001001),
则:a<<3 结果为01110(对应二进制数为0000001001001000),a的符号不变
a>>4 结果为4(对应二进制数为0000000000000100),a的符号不变
又如,设短整型变量a为-4(对应二进制数为1111111111111100),
则:a<<3 结果为-32(对应二进制数为1111111111100000),a的符号不变
a>>4 结果为-1(对应二进制数为1111111111111111),a的符号不变
你明白吗?知道这些结果咋来的吗?
因为我个人感觉这一块比较重要,所以我要说明白:
左移运算符是用来将一个数的各二进制位左移若干位,移动的位数由右操作数指定(右操作数必须是非负值),其右边空出的位用0填补,高位左移溢出则舍弃该高位.
例如:将a的二进制数左移2位,右边空出的位补0,,左边溢出的位舍弃.若a=5,二进制表示a=00001111,左移2位得到00111100.
你看看源代码:
#include <stdio.h>
void main()
{
int a=15;
printf("%d\n",a<<2);
}
左移1位相当于该数乘以2,左移2位相当于该数乘以2*2=4,15<<2=60,即乘了4.但是这个结论只适用于该数左移时被移除舍弃的高位不包含1的情况.
结社以一个字节(8位)存一个整数,若a为无符号整型变量,则a=64时,左移一位时溢出的是0,而左移2位时,溢出的高位中包含1.
右移运算符
右移运算符是用来将一个数的各二进制位右移若干位,移动的位数由右操作数指定(右操作数必须是非负
值),移到右端的低位被舍弃,对于无符号数,高位补0。对于有符号数,某些机器将对左边空出的部分
用符号位填补(即“算术移位”),而另一些机器则对左边空出的部分用0填补(即“逻辑移位”)。注
意:对无符号数,右移时左边高位移入0;对于有符号的值,如果原来符号位为0(该数为正),则左边也是移
入0。如果符号位原来为1(即负数),则左边移入0还是1,要取决于所用的计算机系统。有的系统移入0,有的
系统移入1。移入0的称为“逻辑移位”,即简单移位;移入1的称为“算术移位”。
例: a的值是八进制数113755:
a:1001011111101101 (用二进制形式表示)
a>>1: 0100101111110110 (逻辑右移时)
a>>1: 1100101111110110 (算术右移时)
在有些系统中,a>>1得八进制数045766,而在另一些系统上可能得到的是145766。Turbo C和其他一些C
编译采用的是算术右移,即对有符号数右移时,如果符号位原来为1,左面移入高位的是1。
源代码:
#include <stdio.h>
main()
{
int a=0113755;
printf("%d",a>>1);
}
在不明白自己看书吧.....