操作符详解
操作符分类

原码、反码、补码
整数的2进制表示方法有三种,即原码、反码、补码。
有符号的三种表示方法均有符号位和数值位两部分组成。
首位被当作符号位,剩下的均为数值为。
符号位用0表示正,用1表示负。
正整数的原码、反码、补码都相同。
负整数的三种表示方法各不相同。
- 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
- 反码:原码的数值位取反,符号位不变。(0变1,1变变0)
- 补码:反码 + 1。
例如:
对于整型来说,其实存放在内存中的就是他的补码。
1 | int a = -10; |
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将
符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法
器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路
移位操作符

全程操作的都是数据的补码。
##3.1 左移位操作符
移位规则:左边抛弃,右边补0
1 | int a = 10; |

1 | int a = -10; |

右移位操作符
右移位操作符分两种情况:逻辑右移和算术右移
逻辑移位规则:右边抛弃,左边补0
1 | int a = 10; |

算术移位规则:右边抛弃,左边用概该数的符号位填充
1 | int a = -10; |

对于移位操作符,不能移动负数位,这个标准是未定义的。
位操作符
1 | & // 按位与 |
注:他们操作的必须是整数。
& 是双目操作符,对两个数的补码进行操作,都为1是1,有0就是0
| 是双目操作符,对两个数的补码进行操作,有1就是1,都是0位0
^ 是双目操作符,对两个数的补码进行操作,位相同为0,不同为1
1 | nt num1 = 10; |

使用位操作符实现交换两变量的值
假设现在有一变量 x
那么 x 一定满足 x ^ x = 0, 0 ^ x = x
对于变量 a,b ,满足 (a ^ b) ^ c = a ^ (b ^ c)
即可推导出
1 | int a = 0; |

求一个整数存储在内存中的二进制中的 1 的个数
对于 1 来说,他与任意一个整数进行 & 运算只会出现 0 和 1 两种结果。
1 | 00000000 00000000 00000000 00000001 // 1在内存中的存储 |
那么就可以这么设计
1 | // 计算一个整数的二进制表示中有多少个 1 |

还有一种效率更高的算法,不需要循环32次
1 | int num = -1; |
这个算法利用的就是每次 num & num - 1 会将这个数放在末尾的1消掉。
直到这个数变成0为止,统计这个过程执行了多少次,就知道 num 的二进制表示中有多少个 1 了。

注:只有在补码存储下该公式成立
逗号表达式
就是指用逗号隔开的多个表达式。
从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
1 | int a = 3; |

这儿有一串代码
1 | a = test1(); |
那么根据逗号表达式的计算,还可以这么写
1 | while (a = test1(), test2(), a > 0) |
标访问[]和函数调用()
这俩没啥好说的
1 | int arr[10];// |
1 | void test1() |
结构体访问操作符
这一块儿放到后面结构体一块儿说。
表达式求值
整型提升
C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整
型,这种转换称为整型提升。
1 | char a = 3; |

这里 a 和 b 在进行相加之前,就会先提升为普通整型,再执行加法计算。
计算完成后,结果在被截断后存放进 c 中。
整型提升的规则是
有符号整数提升是按照变量的数据类型的符号位来提升的
无符号整数提升,高位补0
1 | char c = a + b; |
所以最后输出的是 -126
算术转换
如果某个操作符的各个操作数属于不同的类型,那么需将其中一个操作数的类型
转换为另一个操作数的类型。
如果某个操作数的类型在上面这个列表中排名靠后,那么首先要转换为另外一个操作数的类型后执行运算。



