前言:本节内容介绍的操作符,操作的对象是二进制位。所以前面先介绍整数的二进制位
一、二进制位介绍
1.二进制介绍
(1)整数的二进制表示形式有三种:原码、反码和补码。
(2)原码、反码和补码的长度有数据类型来决定,如整数,就是四个字节,转化后是三十二位比特位,所以一个整数写成二进制序列的时候,是32个bit位。
(3)数据是以补码的形式在内存中存储的。
(4)正负数原码、反码和补码不一样
2.正数三码的介绍
(1)正数的原码、反码和补码都一样,不需要计算,可以直接得出来。
(2)举例
7,我们先把7转化成二进制数:111;由于整数的二进制序列是32位,所以其他我需要补0,就写成这样
原码:00000000 00000000 00000000 00000111
反码:00000000 00000000 00000000 00000111
补码:00000000 00000000 00000000 00000111
3,二进制数为:11 二进制序列:
原码:00000000 00000000 00000000 00000011
反码:00000000 00000000 00000000 00000011
补码:00000000 00000000 00000000 00000011
3.负数三码的介绍
我们接下来重点介绍负数的原码、反码和补码
(1)原码
对于有符号的整数来说,最高位的一位是符号位;符号位是1表示负数,符号位是0表示正数。若是无符号数,没有符号位,所有位都是有效位。数字0则当成无符号数来看待。
正数:
负数:
对于有符号数来说,正负数原码的差异就是在最高位。
(2)反码
1.反码,顾名思义就是取反。
定义:反码是在原码的基础上,除了符号位,其他按位取反,1的话就写成0,0就写成1。
2.-7的反码
原码:10000000 00000000 00000000 00000111
反码:11111111 11111111 11111111 11111000
(3)补码
1.定义:补码则是在反码的基础上+1。
2.-7的补码
原码:10000000 00000000 00000000 00000111
反码:11111111 11111111 11111111 11111000
补码:11111111 11111111 11111111 11111001
而补码,就是数据在内存中的存储形式。所以整数在计算的时候使用的也是补码。
总结:三码的转换规则:原码----(取反)--->反码-----(+1)---->补码
补码----(-1)--->反码----(取反)--->原码
补码----(取反,+1)--->原码
二、移位操作符
前言:移位操作符包括左移操作符(<<)和右移操作符(>>)
1.左移操作符(<<)
(1)常用口诀:左边丢弃,右边补0
(2)代码演示
#include<stdio.h>
int main()
{
int a = 7;
int b = a << 1;//a向左移动一位
printf("%d\n",a);//a的本质没有改变
printf("%d\n",b);
return 0;
}
代码结果:
由上面很清楚的就可以知道,其实a的值还是-7,没有改变。
代码演示2:
#include<stdio.h>
int main()
{
int a = -7;//将a的值改成负数
int b = a << 1;
int c = a << 2;
printf("%d\n",a);
printf("%d\n",b);
printf("%d\n",c);
return 0;
}
运行结果:
两次代码演示初步总结:左移一位,结果在原数据基础上×2;左移两位,结果在原数据基础上×3;但原数据的值不会改变。
(3)左移符号解析
左移符号,移动的是补码,但是打印的时候打印的是原码。
正数左移:7
原码:00000000 00000000 00000000 00000111
反码:00000000 00000000 00000000 00000111
补码:00000000 00000000 00000000 00000111
正数的左移比较容易看出来,因为原码、反码和补码都相同
负数右移:-7
原码:10000000 00000000 00000000 00000111
反码:11111111 11111111 11111111 11111000
补码:11111111 11111111 11111111 11111001
总结:
无论正数还是负数,左移的结果都会×2。
记忆口诀:左边丢弃,右边补0。
2.右移操作符(>>)
(1)右移操作符分类
右移操作符包括:算术右移和逻辑右移
逻辑右移:右边直接丢弃,左边补0
算术右移:右边直接丢弃,左边补原符号位(正数补0,负数补1)-----------常用选择
我们下面的例子也都用算术右移来演示
(2)代码演示
#include<stdio.h>
int main()
{
int a = 10;
int b = a >> 1;
printf("%d\n", a);
printf("%d\n", b);
int c = -10;
int d = c >> 1;
printf("%d\n", c);
printf("%d\n",d);
return 0;
}
运行结果:
其实不难发现,算术右移其实也有一种÷2的效果。
(3)右移图示解析
总结:大多数编译器都是使用算术右移,效果相当于÷2
算术右移口诀:右边丢弃,左边补原符号位
3.左移、右移总结
(1)移动的对象只能是整数
(2)只能移动正整数位,比如左移一位、右移两位。
(3)移动后不会改变原数据的值
(4)移动的是二进制的补码,打印的结果是二进制的原码
三、位操作符
前言:位操作符的对象仍然是二进制的补码,他们必须有两个操作对象
1.按位与(&)
(1)定义
两个对象的补码比较,相同位有0则结果位0,相同位都是1结果才为1。
(2)代码演示
#include<stdio.h>
int main()
{
int a = 5;
int b = 7;
int c = a & b;//将按位与的结果赋值给c
printf("%d\n",c);
return 0;
}
运行结果:
(3)代码分析
我们先列出5和7的补码:
5的补码:00000000 00000000 00000000 00000101
7的补码:00000000 00000000 00000000 00000111
图解:
(4)实列讲解
根据有0为0,两个1才为1的特点,可以按位与1来确定最低一位(最右一边)是1或者0。
代码演示:
#include<stdio.h>
int main()
{
int a = 3;
int b = a & 1;
printf("%d\n",b);
return 0;
}
运行结果:
结果分析:
3的补码:00000000 00000000 00000000 00000011
1的补码:00000000 00000000 00000000 00000001
所以,任何数按位与1,得出的结果为1,则该数的二进制最低为是1,如果是0,则最低为是0。当然,要知道该数的二进制序列的所以1,则需要配合右移符号使用(后续补充)
2.按位或(|)
(1)定义
二进制序列对应位上,有1则为1,两个相同才为0。
(2)代码演示
#include<stdio.h>
int main()
{
int a = 5;
int b = -3;
int c = a | b;//按位或
printf("%d\n",c);
return 0;
}
运行结果:
(3)代码解读
5的补码:00000000 00000000 00000000 00000101
-3的补码:11111111 11111111 11111111 11111101
3.按位异或(^)
(1)定义
对应的二进制位相同为0,相异为1
由此而来的知识点:a^a=0 a^0=a
(2)代码演示
#include<stdio.h>
int main()
{
int a = 5;
int b = -3;
int c = a ^ b;//按位异或
printf("%d\n", c);
return 0;
}
运行结果:
(3)代码解读
5的补码:00000000 00000000 00000000 00000101
-3的补码:11111111 11111111 11111111 11111101
(4)实例讲解
题目:在不借助第三方变量的情况下,交换两个变量的值
代码演示:
#include<stdio.h>
int main()
{
int a = 520;
int b = 1314;
a = a ^ b;
b = a ^ b;//此时的a=a^b
a = a ^ b;
printf("a=%d b=%d\n",a,b);
return 0;
}
运行结果:
代码解读:
第一步:a=a^b;这个结果先不要算出来
第二步:b=a^b;这个时候左边的a=a^b,所以整个等式变成b=a^b^b,因为b^b=0,且a^0=a,所以此时就将a的值赋给了b,
第三步:a=a^b,此时左边的a=a^b,b=a,所以左边=a^b^a=b,所以就将b赋值给了a,完成两个数的交换
四、某些复合赋值操作符和一个单目操作符
前言:操作对象都是二进制的补码
1.复合赋值操作符
(1)赋值操作符的介绍
(2)使用方法
上面的这些符号就多了一个等号,就如同+=一样
代码举例:
#include<stdio.h>
int main()
{
int a = 5;
a = a >> 1;//普通写法
a >>= 1;//复合写法
a = a << 1;
a <<= 1;
a = a & 2;
a &= 2;//复合写法
a = a | 4;
a |= 4;
a = a ^ 1;
a ^= 1;
return 0;
}
2.一个单目操作符
(1)定义:~(一个波浪号)
作用:对一个数的二进制按位取反
(2)代码演示
#include<stdio.h>
int main()
{
int a = 0;
printf("%d\n",~a);//单目操作符
return 0;
}
运行结果:
(3)例子
#include<stdio.h>
int main()
{
int a = 10;
a |= (1 << 4);//控制二进制将10变成26
printf("%d\n",a);
//再将26变回10
a &= (~(1 << 4));
printf("%d\n",a);
return 0;
}
10的补码:00000000 00000000 00000000 00001010
26的补码:00000000 00000000 00000000 00011010
10变成26:
26变回10:只需将该位置按位与上0即可