1. 操作符的分类
算数操作符:+ - * / % (都是双目操作符)
移位操作符:>> <<
位操作符:& | ^
赋值操作符:= += -= *= /= %= <<= >>= &= |= ^=
单目操作符:! ++ -- &(取地址) *(解引用) +(正数) -(负数) ~(按位取反) sizeof (类型)
关系操作符:> >= < <= == !=
逻辑操作符:&& ||
条件操作符:? :
逗号表达式:,
下标引用:[ ]
函数调用:( )
结构成员访问:. ->
2.二进制和进制转换
进制只是数字的表示形式,几进制表示的是每一位上的权重的计算方式
用十进制中的 15 举例
二进制:1111
八进制:17
十进制:15
十六进制:F
最后一位权重是进制的零次方,倒数第二位权重是进制的1次方,依次类推
在程序中,八进制数字以0开头,十六进制数字以0x开头 例如:05(八进制) 0x5(十六进制)
2.1 十进制转二进制
这里用125举例
2.2 二进制转八进制、十六进制
八进制:从右向左每3个二进制数转成一个八进制数
十六进制:从右向左每4个二进制数转成一个十六进制数
3. 原码、反码、补码
整数的二进制表示形式有三种:原码、反码、补码
有符号整数的三种表示方法均有 符号位 和 数值位 两个部分,二进制序列中,最高位被当作符号位,其余都是数值位
符号位 1为负数,0为正数
正整数的原反补都相同,负整数的三种表示方式不一样
源码:就是原数按正负的二进制表示
反码:符号位不变,数值为安慰取反
补码:反码 + 1
对于整形来说,数据存放在内存中用的是补码,计算过成中用的也是补码
原反补转换关系
4. 移位操作符
移位操作符只能针对整数
4.1 左移操作符 <<
移位规则:左边抛弃右边补0
4.1右移操作符 >>
逻辑右移:左边补0,右边丢弃
算数右移:左边补原符号位,右边丢弃
右移到底是逻辑还是算数取决于编译器,大部分编译器是算数右移
对于移位操作符不要移动负数位,这是标准未定义的 例:10 >> -1
5. 位操作符
& 按位与:只要有0就为0,两个同时为1才是1
| 按位或:只要有1就为1,两个同时为0才是0
^ 按位异或:相同为0,相异为1
~ 按位取反:单目操作符,包括符号位,都按位取反
它们的操作数必须是整数
实例1:不能创建临时变量,交换两个整数
可以将异或理解成一种加密 a^b 完成加密,用 a 或者 b 异或密码就完成解密,得到另一个值 b 或者 a
实例2:求一个整数存储在内存中的二进制中的1的个数
方法2
这第二种方法的原理就是用阶除将十进制数转换成二进制数的思想核心
方法3
n&(n-1)
第三种方法非常巧妙用到了 n&(n-1) 它大大简化了相比于第一种方法的运算量,第一种方法固定要计算32次,但是这种方法有几个1就只用计算几次
n&(n-1) 的作用是可以去掉二进制数中的最后一个1,取了几次1变成0说明有几个1
这种思想值得记住,灵活运用会产生更好的效果
实例3:将13的二进制的第五位变成1再变回0
解决这道题要灵活运用移位操作分和按位取反操作符
13: 00000000 00000000 00000000 00001101
1 << 4: 00000000 00000000 00000000 00010000
~(1<<4): 11111111 11111111 11111111 11101111
6. 单目操作符
! ++ -- &(取地址) *(解引用) +(正数) -(负数) ~(按位取反) sizeof (类型)
7. 逗号表达式
exp1, exp2, exp3
逗号表达式,从左向右依次执行。整个表达式结果是最后一个表达式的结果
8. 下标引用操作符[] 函数调用操作符()
[ ] 操作数:数组名 + 下标
( ) 操作数:函数名 + 参数
9. 结构成员访问操作符
9.1 结构体
结构体是一种自定义类型,数组也是一种自定义类型,用来描述复杂对象
结构是一些值的集合,这些值成为成员变量。每个结构体成员可以是不同类型的变量。 如:标量,数组,指针,甚至是其他结构体
9.1.1 结构体声明
举例
9.2 结构体成员访问操作符
9.2.1 结构体成员直接访问
. 结构成员访问操作符
结构体变量 . 成员名
在之前那段代码的基础上展示其用法
9.2.2 结构体成员间接访问操作符
结构体指针 -> 成员名
详细内容在结构体章节中讲解,本章意在展示各种操作符
10. 操作符的属性:优先级、结合性
10.1 优先级
相邻操作符,优先级高的先运算
括号可以改变优先级,括号中的先算
10.2 结合性
当相邻操作符优先级一致,一般是从左向右结合,只有少数操作符从右向左结合,比如赋值操作符
11. 表达式求值
11.1 整型提升
C语言中整形算数运算符总是至少以 int类型 的精度进行计算的,为了获得这个精度,表达式中的字符和短整型变量在使用前被转换为 interesting整形,这种操作被成为整型提升。
11.2 算数转换
如果某个操作符的各个操作数属于不同类型,那么除非其中一个操作数转换成另一个操作数的类型,否则操作数无法执行。
默认情况下,会将精度更低的变量算数转换成精度更高的变量
11.3 问题表达式
11.3.1 第一种
计算路径不为一,先算第一个加号还是第三乘号?
11.3.2 第二种
左侧的c什么时候准备好,是在--c之前还是之后?
11.3.3 第三种
三个fun()函数的调用顺序是什么?
11.3.4 第四种
是先把自增都执行完变成3个 i==4 相加,还是先算前两个自增再相加,再算下一个自增再相加 3+3+4 ?
11.4 总结
即使有雷操作符的优先级和结合性,写出的代码有时也不能拥有唯一的计算路径,那这个表达式就是有风险的,建议不要写出特别复杂的表达式,尤其在表示中用到自增和自减的时候要格外注意。