位运算符
& 按位与
| 按位或
^ 按位异或
~ 按位取反
<< 按位左移
>> 按位右移
除了~(按位取反)是单目运算符,其他的都是双目运算符,结合性从左到右位运算符都是按比特位展开来进行运算的且运算的操作数都必须是整数
按位取反
听名字就知道这东西和逻辑运算符的!有点像,他们两个都是单目运算符,而且运算规律也是一样的,就是取反嘛,但是按位取反的操作数必须为整数,而逻辑非却没有这个要求。
按位与(&)
讲道理,这个不就和逻辑与差了一半吗,而且运算规律也是一样:
a b a&b
1 1 1
1 0 0
0 1 0
0 0 0规则:当两个操作数都为1时才为1否则为0,但是我们前面讲过逻辑运算符都有惰性,所以位运算符也应该是有惰性的,而位运算符和逻辑运算符最大的区别可能就是位运算符是只针对整数的(所以如果对小数或者什么用位运算符那就肯定错了),因为它是按比特位来运算的
按位或(|)
嗯,没错依然和逻辑或有着奇妙的联系,不说多了
按位异或(^)
终于出现个不太一样的,按位异或用人话来讲就是求异的,不同就通过,相同就不通过,所以
3 ^ 6 = ? //5
00000000 00000000 00000000 00000011 3
00000000 00000000 00000000 00000110 6
00000000 00000000 00000000 00000101 5上面这个就是按比特位操作的演示,其实就是把补码写出来,按照运算规律来就欧克、
一个bit 位与 0 进行"按位异或 ^ " 操作 ,结果为 x (保留原值)
x ^ 0 => x
一个bit位与1进行"按位异或 ^ "操作 ,结果 ~x(取反)
x ^ 1 => ~x
红色部分这种规律前面几个也都可以写,但是没必要总结了,这规律和直接算没啥区别,并不能使问题更简洁
按位左移(<<)
一样的看字面意思也能看出来啥意思,看个例子吧:
int a = 8 << 2;
00000000 00000000 00000000 00001000 << 2
000000 00000000 00000000 0000100000很清楚,她就是把一个整数按比特位展开,左边的操作数是你要运算的,右边的操作数就是你需要左移的步数,左移两位其实就是去掉最左边两个数字,然后再最右边补两个0,那么如果左移舍弃的高位都为0,那么左移n位,就在原值乘以2的n次方
按位右移(>>)
这个操作和按位左移还是有些差别,但不过基本的还是一样,按位右移就是先去掉最右边的x个比特位,然后往最左边补上x个就行,但是这个就不是一味的补0就行了:
对于无符号数(x) ,高位全部补0;
对于有符号数(x),高位全部补符号位
#include<stdio.h>
int main()
{
int H = -1>>31;
unsigned int P = -1;
P = P>>31;
printf("%d\n",H);
//-1:11111111 11111111 11111111 11111111
//a>>31:11111111 11111111 11111111 11111111
//所以为:-1
printf("%u\n",H);
//-1:11111111 11111111 11111111 11111111
//a>>31:11111111 11111111 11111111 11111111
//所以为:2^32-1
printf("%d\n",P);
//-1:11111111 11111111 11111111 11111111
//a>>31:00000000 00000000 00000000 00000001
//所以为:1
printf("%u",P);
//-1:11111111 11111111 11111111 11111111
//a>>31:00000000 00000000 00000000 00000001
//所以为:1
return 0;
}
关于这段代码我在写的时候是颇有疑惑的,
unsigned int P = -1;
P = P>>31;这两句代码我将其改写为:unsigned int P = -1>>31时,得到的答案是和有符号数时相同,但本不该如此的,但是我一直没有找到错误的地方,先留在这,有待解决
掩码(mask)
掩码(mask) 是一个位模式 ,表示从一个字(word ,32bits..)中选出的位集合
掩码中为1的那些bit位,就是我们想要选取的bit位集合.
如 :
如果我要选取的 第0bit 和 第1bit ,则掩码位 : 0x3
00000000 00000000 00000000 00000011如果MASK = 0xff,表示要选取低8位
00000000 00000000 00000000 11111111例子 :
假设有一个整型变量x = 0x345678AB,我想要选取x的低8位,该如何操作?
低8位的掩码 mask = 0xff,
x & mask => x & 0xff => 0xAB
关于位运算符的一些计算
假设有一个整型变量a,要把a的第5 bit,变为0,其他bit位不变,该如何去操作.
a = a & ~(1<<5)
思路也很简单,先把a按比特位去展开,这边假设展开后全是x,那么首先我们要想到的就是,如何操作让其保持不变,其实有两个操作:x&1 or x|0,但是还要保证第5bit为0,那么“|”操作就不行了,所以选择了“&”,也就是说我们需要的 第二个操作数除了第5bit是0以外,其他都是1
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
11111111 11111111 11111111 11111111 11011111
这个数不大好表示我们其实也看得出取反后全是0不就好表示了嘛hh
假设有一个整型变量a,要使a的第5bit置1,其他bit位不变,该如何操作?
a = a | (1 << 5)
与上题相似
C语言入门(七)之进制、位运算、左移右移_Vencent Kim的博客-CSDN博客这位兄弟题目挺好的可以参考。
赋值运算符
赋值运算符的优先级很低很低仅排在逗号运算符之前,也是使用频率最高的运算符,赋值运算符它的左边是个左值,这个左值是需要具备有一个可写地址,右边的称为右值,是一个表达式。H=P这么写意思是将P这个表达式的值,写入到H的地址当中去。
5 = 5 ;//error
2 + 3 = 5;//error
int x = 2,y = 3;
x + y = 5;//error
x = 5;//正确的
x++ = 6;//error虽然看起来简单的赋值表达式,但是这些例子估计咋一看要你区分对错还是有点模棱两可的
复合赋值运算符 : 赋值运算符可以和算数运算符,位运算符组合成复合运算符.
+= -= *= /= %=
<<= >>= |= &= ^=比如:
a += b ==> a = a + b
sum <<= 5 ==> sum = sum << 5
sum -=i ==> sum = sum - i
条件运算符
?:这是一个三目运算符了,这个运算符的结合性依然是从左到右,后面通过一个例子可以很清楚的看懂它的运算规律
#include<stdio.h>
int main()
{
int H,P,x;
H = 1;
P = 2;
/*if(H>P)
{
x = H;
}
else
{
x = P;
}*/
x = H>P?H:P;
printf("%d",x);
return 0;
}//一看就晓得了,这个条件运算符不就是发挥了这个if else 的作用吗,
逗号运算符
这是运算优先级最低的一个运算符,他的运算规则也比较简单,比如a = 1,2;那么a = 2,反正就是逗号运算符永远等于最右边那个表达式的值(所以我也不知道为啥还要发明这个东西,明明把最右边的写上去不就行了)但是逗号运算符容易与一些其他的东西搞混,比如:
a = 3,2 这是一个逗号表达式
a = (3,2) 这是一个赋值表达式, 把"表达式(3,2)的值",赋值给a
a = 3,a = 2 这是一个逗号表达式//输出a = 2
a = 3,a = 2,a = 4 这也是逗号表达式 ==> (a = 3,a = 2),a = 4 //输出a = 4
虽然说阿,这个逗号表达式只要了最右边的那个值,但是你在计算机中使用的时候,计算机还是会把前面所有的表达式的值全部计算,最后才算最右边的,因为结合性就是从左到右!!!
指针运算符(重要!!!)
* 指向运算符
& 取地址符
后面再复习
求字节运算符
siazeof(后面也会有这个的复习)
分量运算符
.
->
下标运算符
[] 取数组的元素
int a[10];
a[0]
a[1]
....
强制类型转化运算符
(类型)表达式
如 :
(int)3.5
(int)(3.1 + 4.7)
先后顺序以及结合性
之前都是分散的提到了各类运算符的优先级以及结合性,下面给出一个大表综合的写出
运算符 结合性
() [] -> . 从左到右
! ~ ++ -- +(正号) -(负号) * &(取地址符) sizeof 从右到左
* / % 从左到右
+ - 从左到右
<< >> 从左到右
< <= > >= 从左到右
== != 从左到右
& 按位与 从左到右
^ 按位异或 从左到右
| 按位或 从左到右
&& 从左到右
|| 从左到右
? : 从右到左
= += -= *= /= %= &= 从右到左
^= |= <<= >>= 从右到左
,