1:(位与)运算符(&):双目操作符,当两个位进行相与时,只有两者都为“1”时结果才为“1”(即:全真为真,一假为假),运算规则如下:
左运算量 右运算量 &运算结果
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
运算:
例:
#include <stdio.h>
int main(int argc,char *crgv[]){
unsigned char x=0156, y=0xaf, z
z=x&y
printf("%d",z)
}
结果为:0x2e
运算过程:0156(8进制)==0000 0110 1110(2进制);
进行 &(位与运算)
0xaf(16进制) ==0000 1010 1111(2进制);
结果:0000 0010 1110(2进制)==0x2e(十六进制);
2:位或运算符(|):
双目操作符,当两个 位 进行相或时,两者中只要有一方为“1”,结果就为“1”(即:一真为真,两假为假),运算规则如下:
左运算量 右运算量 (|) 运算结果
0 | 0 = 0
1 | 1 = 1
0 | 1 = 1
1 | 1 = 1
例:
#include <stdio.h>
int main(int argv,char *argc[]){
unsigned char x=027,y=0x75
z=x|y
}
运行过程:
027(8进制)=0001 0111(2进制)
进行 |(位或运算)
0x75(16进制)=0111 0101(2进制)
结果:0111 0111(2进制)=0x77(16进制)
3.异或运算(^):
当两个位进行异或时,只要两者相同,结果为“0”,否者结果为“1”,(即:同假异真)运算规则如下:
左运算量 右运算量 (^) 运算结果
0 ^ 0 = 0
1 ^ 1 = 0
0 ^ 1 = 1
1 ^ 0 = 1
例:
#include
int main(int argv,char *argc[]){
unsigned(无符号) char x=25,y=0263,z
z=x^y
printf("%d\n",z)
}
运算过程:
25(十进制)=0001 1001(二进制)
运算 ^(异或运算)
0263(8进制)=1011 0011(二进制)
结果:1010 1010(二进制)=0252(8进制)
4:移位操作符(“<<” 或 ">>"):位移位运算的一般形式:<运算量><运算符><表达式>;
<运算量>必须为整型结果数值:
<运算符>为左移位(<<)或 右移位(>>)运算;
<表达式>也必须为整型结果数值;
移位操作就是把一个数值左移或右移若干位;假如左移n位,原来值最左边的n位数被丢掉,右边n卫补“0” ;右移操作就是和左移操作移动方向相反;
符号位的处理方法:
(1):逻辑移位,不考虑符号问题,原数值右移n位后,左边空出的n歌位置,用0填充;
(2):算术移位,原来值进行了右移操作后,需要保证符号位不变,因此,右移n位后,左边空出的n个位置,用原数值的符号位填充。原来若是负数,则符号位为“1”,填充的位也是“1”;原来若是正数,则符号位为“0”,填充的位也是“0”,这样保证移位后的数据与原数正负相同;
例:“1000 1001”将其右移两位,逻辑移位的结果为“0010 0010”,算术移位为:“1110 0010”;
将其左移两位,逻辑移位和算术移位的结果为:“0010 0100”;
(3)***补充:特定位清零(由“1”变成“0”)用 位与 操作;特定位变“1”(由“0”变成“1”)用 位或操作;
例:
a、请把0xd5的第2位进行清零操作
0xd5=1101 0101=>1101 0001
1111 1011
~0000 0100
=0000 0001<<2
~(0x01<<2)&0xd5
b、请把0xed的第3位进行清零操作
0xed=1110 1101=>1110 0101
1111 0111
~
0000 1000
= 0000 0001<<3
~(0x01<<3)&0xed
c、请把0x7d的第2-4位进行清零
0x7d=0111 1101=>0110 0001
1110 0011
~
0001 1100
=
0000 0111<<2
~(0x07)&0x7d
d、请把0x7d的第2位和第3位进行清零
0x7d=0111 1101=>0111 0001
1111 0011
~
0000 1100
0000 0011<<2
~(0x03<<2)&0x7d
e、请把0xc7的第4位进行置1
0xc7=1100 0111=>1101 0111
0001 0000
=0000 0001<<4
=~(0x01<<4)|0xc7
f、请把0x87的第3位进行置1
0x87=1000 0111=>1000 1111
0000 1000
~(0x01<<3)|0x87
g、请把0xc7的第3—5位置1
0xc7=1100 0111=>1111 1111
0011 1000
0000 0111<<3
~(0x07<<3)|0x87
c语言位运算问题解答:
要解答这个问题我们先来看一个例子,代码如下图一,图中右边是问题中得到代码,左边是这段代码的汇编指令。两种情况的不同点详细说明如下:
第一种情况:
printf("%d",2>>64)
由图中的汇编代码可以看出,如果两个数都是常数的情况下,代码中是不含对应的汇编指令的,因为编译器已经省略了,编译器算出结果为0,直接把0传入给printf函数。
第二种情况:
int i=2
printf("%d",i>>64)
此时i是个变量,编译器没法在编译时算出结果,这时就需要通过SARL算术右移指令进行,这里考虑到溢出这个指令有一个调整机制,它会根据左操作数i类型来调整右操作数,比如这里i是4字节32位,也就是它最多右移32位,如果右操作数大于32它会进行64%32=0,所以i>>64相当于i>>0,如果是i>>63,63%32=31相当于i>>31。这种调整不同的编译器可能会不同,目前GCC是这样的。
所以这个代码在GCC环境下输出结果为:
0
2
补充说明:如果想要了解更多可以写出代码,然后观察编译出来的汇编代码。
gcc -S test.c
图一