ʕ • ᴥ • ʔ
づ♡ど
🎉 欢迎点赞支持🎉
个人主页:励志不掉头发的内向程序员;
专栏主页:C语言基础;
文章目录
前言
一、操作符的分类
二、二进制和进制转换
2.1 二进制转十进制
2.1.1 十进制转二进制
2.2 二进制转八进制和十六进制
三、原码、反码、补码
四、移位操作符<< >>
4.1 <<
编辑
4.2 >>
五、位操作符&、|、^、~
5.1 按位与&
5.2 按位或
5.3 按位异或^
5.4 按位取反~
总结
前言
大家好呀,本章节我打算来和大家来详细的说说操作符,我们前几章节也说过了部分的操作符,在这一章节我们来完善和具体的再来说说,操作符有很多很多,它们之间各自有着各自的作用,可以说每一个都缺一不可,所以说我们大家一起来好好学习学习吧。
一、操作符的分类
以上便是所有的C语言操作符,在这之中肯定有大家非常眼熟的,当然也有非常多陌生的,现在我们就来讲讲大家陌生的操作符吧,首先是位运算符和移位运算符,它们的主要作用对象是二进制的内容,以防大伙不知道,我们就来讲讲进制转换吧。
二、二进制和进制转换
进制进制,顾名思义就是满多少就进一,十进制就是满十进一,二进制就是满二进一,生活中有各种各样的进制,比如七进制就是我们的一周,60进制就是我们的分钟,24进制就是我们的小时,我们一般普遍使用2、8、10、16进制。其实各种不同的进制只是数值不同的表现形式而已。
2.1 二进制转十进制
我们在了解二进制前可以先拿我们熟悉的十进制下手,来分析分析十进制的规律,比如123,我们读作一百二十三,我们可以发现这三个数字每个的权重都不相同,一个是个位(也就是10的0次方),一个是十位也就是10的1次方),还有一个是百位也就是10的2次方),由此可见,这个123是由3 * 10 ^ 0 + 2 * 10 ^ 1 + 1 * 10 ^ 2 = 123,十进制中的数字只会出现0~9,不可能会超过9,这就是十进制的特征。
我们现在来反推二进制就可以知道,二进制的数字只会出现0~1,也就是0和1,而且权重也是2^0、2^1、2^2等;例如45用二进制表示就是101101,我们来推导一下就知道了:1*2^0 + 0*2^1 + 1*2^2 + 1*2^3 + 0*2^4 + 1*2^5 + = 1 + 0 + 4 + 8 + 0 + 32 = 45;这就是二进制的主要特征,也是二进制转十进制的方式。
我们也可以按照以上的方式来推推八进制,八进制的数字只会出现0~7,而且权重也是8^0、8^1、8^2等。
而十六进制是满16进1,但是阿拉伯数字只有1~10,所以我们就引进了英文数字a~f,所以十六进制只会出现0~f,而且权重也是16^0、16^1、16^2等。
2.1.1 十进制转二进制
在了解了二进制怎么转十进制以后,我们再来看看十进制怎么转二进制,其实也很简单,就是除二取余。如图所示
从下往上读的原因是因为下面除的次数更多,所以说权重更大,就在更左边。当然,如果说有人觉得这种办法蛮难的也没关系,我们既然知道二进制怎么转十进制,我们反推一下不就可以了比如这个十进制的311,我们可以想想二进制可以的最大值是多少,应该是2^8,也就是说二进制应该是1xxxxxxxx,然后我们看看十进制还剩下多少,311-256=55,然后重复步骤,这一次最大是应该是2^5,也就是32,还剩下55-32=23,二进制应该是1001xxxxx,然后再重复,最终得出的结果也是100101111.这就是十进制转换成二进制的方法啦,大家看自己按喜欢方法来就行。
十进制转其他进制的方法也是和上面一样的,这里就不多赘述。
2.2 二进制转八进制和十六进制
我们发现,3个二进制位就能表示一个八进制位比如二进制的111就等于八进制的7,所以说我们把二进制转换成八进制时,就是每三个二进制位转换成一个八进制位,比如1010011011,我们可以把它分为001 010 011 011(不够3位的前面补零),转换成八进制就是1 2 3 3。
二进制转换成十六进制也是如此,我们可以用4个二进制位转换成1个十六进制位,比如:11101001111010011110101,可以把它分成0111 0100 1111 0100 1111 0101(不够的前面补0),转换成十六进制就是7 4 f 4 f 5。
三、原码、反码、补码
整型在计算机中用二进制有3种表示方法,就是原码、反码、补码,可能会有小伙伴们疑惑啦,为什么会有三种,这三种有什么区别嘛,小伙伴们先别急,容我细细说来,我们先来说说我们平时创建的有符号的整型变量在计算机中是如何区分它们的,假如我们创建了一个int a = 10;int b = - 10;那么我们的计算机是如何区分它们之间的区别呢,其实我们有符号整数在计算机中有符号位和数值位两个部分,2进制序列中,最左边的一个二进制位是符号位,剩下的是数值位,就比如a = 00000000000000000000000000001010=10(int型是4个字节,也就是32bit,一个bit代表一个二进制位),而b=10000000000000000000000000001010=-10,看出来了吧,我们二进制最左边的一个二进制位就是符号位,1代表负号,0代表正号,当然,如果是unsigned(无符号类型,前面讲过),那就没有符号位,都是数值位。
我们既然知道了这个道理,那我们就来看看原码、反码、补码吧。
原码:直接将二进制数值按照正负号的形式翻译成二进制得到的就是原码
反码:将原码除去符号位的其他位依次按位取反(0变成1,1变成0)后得到的就是反码
补码:反码+1后得到的就是补码
补码变成原码除了可以按上面的方式反推回去以外,还可以和上面一样:取反,+1。
正数的原码、反码、补码都是一样的,而负数的原码、反码、补码则要按上面的方式变化。例如
int a = 9
原码:00000000000000000000000000001001;
反码:00000000000000000000000000001001;
补码:00000000000000000000000000001001;
int b = -9
原码:10000000000000000000000000001001;
反码:11111111111111111111111111110110;
补码:11111111111111111111111111110111;
对于整型来说:数据存放在内存中的其实是补码
原因是因为补码将数值的符号位和数值域统一处理;同时也将加法和减法统一处理(CPU只有加法器)就比如我们想算9-9,对于计算机而言相当于9+(-9),如果直接用原码相加则是
9: 00000000000000000000000000001001
-9:+ 10000000000000000000000000001001
————————————————————————
-18 10000000000000000000000000010010
发现没,是不是错的离谱,但是我们用补码试试看
9: 00000000000000000000000000001001;
-9: 11111111111111111111111111110111;
————————————————————
补码 00000000000000000000000000000000
我们可以看到符号位是0,也就是说是正数,所以原码、反码、补码相同,所以答案就是0;这就是有原码、反码、补码的原因,也是为什么整型存储的是补码。
四、移位操作符<< >>
1、<<:左移位操作符
2、>>:右移位操作符
注:移位操作符只能操作整数。
4.1 <<
左移操作符的规则是左边丢弃、右边取0
使用方法:
a << 2;
a << 1;
我们来看看它到底是怎么用的吧。
int main()
{
int a = 20;
int b = a << 1;
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
我们发现b比a乘了个2,难道这个左移位操作符就是乘个2嘛,先别急,我们来看看它的补码再说。
我们可以发现,好像就是把a的整体向左移动了一格,然后左边抛弃,右边补0。
我们再来看看负数的左移吧。
int main()
{
int a = -20;
int b = a << 1;
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
我们来看看它们的补码
可以看出来,它也是左边抛弃,右边补0。
4.2 >>
看过左移操作符的小伙伴们再来看右移操作符时肯定就已经认为自己大致明白了,不就是右边丢弃、左边取0嘛,我们可以来看一下是不是这样的。
int main()
{
int a = -10;
int b = a >> 1;
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
变成-5啦,我们来看看它们的补码
我们可以发现,它本来应该右边抛弃,左边补0的,但是左边却补了一个1,这是为什么呢?
其实右移操作符有两种移动方式,
1、逻辑右移:右边抛弃,左边补0;
2、算数右移:左边用原来该值符号位填充,右边抛弃;
vs编译器就是用的第二种,但是有的会用第一种。
移位操作符不能移动负数位哦,大家要注意。
五、位操作符&、|、^、~
&:按位与(&&:逻辑与)
|:按位或(||:逻辑或)
^:按位异或
~:按位取反
我们来直接看看代码吧
int main()
{
int a = 10;
int b = 14;
printf("& = %d\n", a & b);
printf("| = %d\n", a | b);
printf("^ = %d\n", a ^ b);
printf("~ = %d\n", ~b);
return 0;
}
我们来一个一个的看看
5.1 按位与&
a: 00000000000000000000000000001010
b: 00000000000000000000000000001110
&
——————————————————————
10: 00000000000000000000000000001010
通过观察我们可以发现,其实按位与的作用就是如果同时为1就是1,同时为0就是0,否则都是0;
5.2 按位或
a: 00000000000000000000000000001010
b: 00000000000000000000000000001110
|
——————————————————————
14: 00000000000000000000000000001110
通过观察我们可以发现,其实按位或就是如果有一个1那就是1,否则就是0;
5.3 按位异或^
a: 00000000000000000000000000001010
b: 00000000000000000000000000001110
^
——————————————————————
4: 00000000000000000000000000000100
通过观察我们可以发现,其实按位异或就是如果都是相同的则是0,不同的则是1;
5.4 按位取反~
b: 00000000000000000000000000001110
~
——————————————————————
-15: 10000000000000000000000000001111
通过观察我们发现我们什么都没法发现,我们把它们都变成补码看看
b: 00000000000000000000000000001110
~
——————————————————————
-15: 1111111111111111110001
我们可以发现,这就是把b反过来了,这就是按位取反的作用。
我想可能会有小伙伴们要问啦,这有什么用啊,由于篇幅太长,下次再讲啦。
总结
以上便是我们的操作符部分的内容,下节课将给大家讲完大部分的操作符的用法,希望大家的继续观看。感谢大家的观看,如果哪里有误,欢迎支持,谢谢大家。