一,算术操作符:
+ - * / %(加减乘除):
/中如果除数与被除数都是整数形式,得到的是商,有余数;如果至少有一个是小数则所得的结果是小数形式。
%(取模,即取余数)这个操作符两边必须是整数,不能是浮点数。
二,移位操作符
右移操作符(>>);
1算术右移:右边超出部分舍去,左边补 原符号位
2逻辑右移:右边超出部分舍去,左边补0
整数的二进制表示有:原码,补码,反码,在内存中以补码的形式存储
对于正整数来说,原码,反码。补码都是相同的,
对于负数(以-1为例)
原码:10000000000000000000000000000001
反码:1111111111111111111111111111111111110(符号位不变,其他位按位取反)
补码:1111111111111111111111111111111111111(反码+1)
对于-1,右移,无论右移多少位,左边都一直补1,其补码不变,原码也不变,因此-1的算术右移总是-1
左移操作符(<<):
左边超出部分丢弃,右边补零
注意:对于位移操作符,移动的位数不要是负数,这是一个未定义行为,位移操作符只能作用于整数。
三,位操作符(二进制位):只能作用于整数
按位与(&):对应位都为1,才为真(1),否之为假(0)
按位或(|):对应位至少有一个为1,就为真(1),全为0才为假(0)
按位异或(^):对应位相同为假(0),对应位相异,为真(1)
注意计算机中都是拿补码进行运算的,因此负数需要先计算出补码再进行,与,或,异或
下面看几个例子:
1,不用中间变量交换a 和 b的值
2,求一个数存储在内存中二进制中1的个数
四,赋值操作符(=)
变量初始化:数据类型 变量名= 值
赋值:变量名=值(已经有值,改变值叫赋值)
常见的赋值符号:
例如:
五,单目操作符(只有一个操作数)
!a:将a的真假性变换,假变真,真变假
&:&a取出a的地址,一般与指针配合使用
sizeof :用来求大小的,单位是字节
数组去掉数组名,得到的就是数组类型,方括号里面的数字,影响数组的大小
注意这个代码:注意s的类型是short短整形,s=a+5之后,s依然是短整形,多余部分将被截断,因此第一个打印结果是2个字节,而在sizeof内的计算并不是真正的计算,不会改变变量的大小,因此,s的值依然是0。
看一个有关sizeof的题:
这里很容易直到(1)(3)打印的值分别为:40,10,但是(2)(4)呢,这里不要忘记,当把数组传给函数时候,传的是首元素的地址,也就是说是一个指针变量,在32位机上是4个字节大小,在64位机上是8个字节大小。
~:按位取反(按二进制位)
故~0为-1;
一个应用场景(指定位改变二进制数)
++与--:前置是先++或--再使用,后置是先使用再++或--
六,关系操作符
七,逻辑操作符
逻辑与(&&):两边都为真,得到的才是真
逻辑或(||):至少有一边为真结果就为真
注意:逻辑与和逻辑或注意的这个数的本身
按位与和按位或主义的是俩数的二进制对应位
逻辑与(&&)如果左边的结果已经是假,那么 不管右边什么就不会再计算了。如:
这个程序输出为1 2 3 4
原因:a++是先使用a的值,则&&左边是假,后面的 ++b和d++都不会再计算
只有a++,故1,2,3,4
如果将a=0改为a=1,那么都将会计算,执行的结果是2 3 3 5
逻辑或(||)如果左边是真,不管右边是啥都不会再计算
这个结果是:2 3 3 4,原因是a=1,||左边已经是真,则||右边的不管是啥都不会运算
综上:对于逻辑与:如果左边是假,右边将不会再计算,直接返回假
对于逻辑或:如果左边是真,右边也不会再计算,直接返回真
八,条件表达式
exp1?exp2:exp3
解释:如果表达式1为真,就执行表达式2,并且表达式2的结果是整个表达式的结果,如果表达式1为假,就执行表达式3,并且表达式3的结果就是整个表达式的结果。
例如:
需要注意的是,写条件表达式不要写的过于复杂,不利于阅读代码。
九,逗号表达式
有逗号隔开的多个表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
a>b不产生执行结果,a=b+10,得到a=12.a不产生执行结果,b=a+1,得到b=13,因此这个c的值是13
这个真正起到作用的是后面d>0的判断,但是在判断之前,前面的表达式还是要计算的
对于逗号表达式如果不熟悉就不要使用,老老实实的写代码才是硬道理
十,其他操作符
下标引用操作符:[],有两个操作数,分别是数组名,索引数
函数调用操作符:()至少有一个操作数(函数名),传入的参数也是操作数
结构体操作符:.和—>
先创建一个结构体:
对于结构体的访问:
即:结构体变量名.成员名
或者通过指针变量
结构体指针—>成员名
表达式求值:
表达式求值的顺序一部分是由操作符的优先级和结合性决定的,同时有些表达式的操作数在求值时需要数据类型转换
1,隐式类型转换
C的整型算术运算总是至少以缺整型类型的精度进行的,为了获得这个精度,表达式中的字符和短整形在运算前转化为普通整型,这称为:整型提升
对于定义一个比整型小的数据,让他等于一个整型,则要按照所定义的数据类型大小进行截断char只保留一个字节,short只保留2个字节,之后在进行整型运算的时候要进行整型提升,有符号的数按照符号位(也就是原最高位)补在左边,无符号的数,直接补0
例如:
这个程序,c是char类型,本应是一个字节,但是+c做了整型运算,被整型提升为4个字节
算术转换:如果某个操作符的操作数的类型不同,除非其中一个操作数类型转换为另一操作数类型,才能计算
一个操作符如果出现以上两种或两种以上的操作数, 就要进行整型转换,将所占内存小的转换为所占内存大的。
操作符的属性:复杂表达式求值有三个影响:操作符的优先级;操作符的结合性;是否控制求值顺序
对于这个求值表达式,有一下可能路径
,可能的路径:
这就导致可能在不同的编译器出现不同的结果,这种程序是有问题的,自己写的时候要避免
还要这个,c到底是--之前还是之后的值呢,就会有歧义
同样,这段程序,下面调用了三次fun,不同顺序会导致fun返回的结果不同,因此是有问题的。
通过以上这几个例子告诉我们,要尽量避免写复杂的表达式求值,可以多创建几个中间变量,一步步来写。