一.移位操作符
1.左移操作符:左边抛弃,右边补0。
*首先我们要知道一个整型为4个字节,也就是32bit,我举个例子为大家介绍。
在程序运行时都是按整型补码处理的,所以3的补码0011(我只写出后三位)向左移一位就变成了0110,而二进制换算成十进制就是6;
2.右移操作符
右移操作符运行时分为两种,一种是逻辑操作符,一种是算数操作符。
逻辑操作符:左边用0填充,右边丢弃。
算术操作符:左边用原该值的符号填充,右边丢弃。
接下来我举个例子
#具体运行时是逻辑右移还是算术右移取决于编译器,我用的vs2022就是算术右移
#无论是右移还是左移不能移动负位数
二.位操作符:&,|,^
1.&(按位与):对应二进制位,有0为0,两个同为1则为1。
2.|(按位或):对应二进制位,有1为1,两个同为0则为0。
3.^(按位异或):对应二进制位,相同为0,不同为1。
4.~(按位反):对应二进制位,取反,0>1,1>0。
三.例题
1.不能创建临时变量(第三个变量),实现两个数的交换。
#做这个题之前要知道关于^位操作符的几个结论,比较容易推出来,我就不推导了
a^a=0;a^0=a;
但是这种解法显然比创建第三个变量更复杂,更加难理解,所以这样做有几个局限性。
a.只能用于整型间的交换
b.代码可读性差(难理解)
c.代码执行效率也是低于使用第三变量的方法
2.编写代码实现:求⼀个整数存储在内存中的⼆进制中1的个数。(这个题有三种做法)
a.首先我们要知道,类比十进制,一个数一直重复除2,所得的所有余数中1的个数即为二进制中1的个数,所以我们只需要一直除2,知道这个数为0。(但是这种做法不适用于负数)
b.第二种方法我们需要知道一个定理,就是如果n&1=1,那么n的二进制最后一位一定是1,这样我们只需要每次算完过后向右移一位,继续&1,我们设立一个变量count=0,如果某次结果为1,则count++,这样我们只需要循环32次(第一次向右移0位,因为如果移一位,就会导致二进制最后一位无法验证),count的结果就是二进制中1的数量。
c.第三种解法同样需要用到一个结论,也就是(n-1)&n后,n的二进制中会减少一个一
我给大家演示一下
接下来给大家展示一下此方法的代码
四.逗号表达式
逗号操作符,就是用逗号隔开的多个表达式(从左向右以次计算),整个表达式结果为最后一个表达式的结果,如(a=b+1,c=9+1)的结果就是10。逗号表达式用在if语句中时,如if(a=b+1,c=a/2,d>0)里面前两个表达式也会计算,但是if的条件还是d>0。
五.下标访问操作符[ ],函数操作符调用()
eg.arr[5] arr,5为“[ ]"这个操作符的操作数
eg.Add(2,3) Add,2,3为“()”这个操作符的操作数
六.操作符的属性:优先级,结合性
C语言的操作符有俩个重要的属性:优先级,结合性,这个两个属性决定了表达式的求值的顺序
a.优先级:优先级高的操作符先执行(相邻操作符才讨论优先级)
eg.a=1*2+3*4+4*5,计算机计算顺序可能是先算1*2,再算3*4,然后算1*2+3*4,最后算4*5,再加起来;而不是先算1*2,3*4,4*5,再相加因为打三个“*”与第一个“+”不相邻,所以无法讨论优先级
b.结合性:当优先级相同时再看结合性,有的是从左向右算,有的是从右向左,顺序上面那张图里面有
eg.2/3*2 由于“/” “*”优先级相同,所以看结合性,由于* ,/时从左向右,所以先算/,再算*
七.表达式求值
表达式求值前要进行类型转换,当表达式中得值转换到适当类型时才能计算
7.1整型提升表达式中的字符和短整型操作符在使用前被转换为普通整型,即为整型提升
如何提升:1.有符号整数提升是按照变量的数据类型符号位来提升的
2.无符号整数提升,高位补0
eg.
7.2算术转换
如果某个操作符的各个操作数属于不同的类型,那么除⾮其中⼀个操作数的转换为另⼀个操作数的类 型,否则操作就⽆法进⾏。下⾯的层次体系称为寻常算术转换。