C语言运算符学习记录
1.算术运算符
++a和--a:前置++/--是先加减后赋值
a--和a++:后置++/--是先赋值在加减
如 int a=8,b=5;
printf("a=%d b=%d\n", a++, b--);
此时输出的是8 5 因为是后置的++/--,先赋值在加减,但此时在计算机内存里面a已经变成9,b已经变成3了
printf("a=%d b=%d\n", ++a, --b);
此时输出的是10 3 因为是前置++/--,先加减后赋值,内存里a是9,b是3,加减后为10 3 输出就为10 3
2.位运算符
运算符 | 术语 | 示例 | 结果 |
& | 按位与运算 | 011 & 101 | 2个都为1才为1,结果为001 |
| | 按位或运算 | 011 | 101 | 有1个为1就为1,结果为111 |
^ | 按位异或运算 | 011 ^ 101 | 不同的为1,结果为110 |
~ | 取反运算 | ~011 | 100 |
左移运算 | 1010 | 10100 | |
>> | 右移运算 | 1010 >> 1 | 0101 |
取反、左右位移运算需要在补码的基础上运算。
按位与(&)运算:位与位进行比较,如果都为1,则为1,否则为0
按位或(|)运算:位与位进行比较,如果都为0,则为0,否则为1
按位异或(^)运算:位与位进行比较,相同为0,不同为1
按位取反(~)运算:补码取反,再将取反后的补码转为原码;
ps:无符号的数据,取反后最高位为1,也不需要逆运算。
-
对于无符号数据,取反就是简单的按位取反,取反后的值是一个有效的无符号数,且不需要通过逆运算来恢复原始值。
2.1按位取反运算:补码取反,再将取反后的补码转为原码。
1、正数取反:由于正数的原码和补码是相同的,取反的方式简便了些。
补码(原码) -> 取反 -> 补码逆运算 -> 反码逆运算(符号位不变) -> 取反后的原码
2、负数取反:
原码 -> 反码 -> 补码 -> 取反 -> 取反后的补码即原码
示例:
原码(补码) 取反的补码 补码逆运算-1 反码逆运算
~40 = 0010 1000 -> 1101 0111 -> 1101 0110 -> 1010 1001 = -41
原码(补码) 取反的补码 补码逆运算-1 反码逆运算
~15 = 0000 1111 -> 1111 0000 -> 1110 1111 -> 1001 0000 = -16
原码 反码 补码 取反
~-15 = 1000 1111 -> 1111 0000 -> 1111 0001 -> 0000 1110 = 14
2.2左移运算符和右移运算符:
左移运算符:<< 是将数字的二进制补码全部向左移动,空出来的位置补0,超出范围的二进制数丢弃;
有符号的数据左移后最高位如果为1,则需要进行逆运算;
右移运算符:>> 分为两种情况,逻辑移位和算术移位(正数和负数)
逻辑移位:将数字的二进制补码全部向右移动,空出来的位置补0,超出范围的二进制数丢弃
算术移位:左边移入的位由原先该值的符号位决定,符号位为1,则移入的位均为1,符号位为0,则移入的位均为0,这样能保证原数的正负形式不变
标准规定,无符号值执行的所有位移操作都是逻辑移位,对于有符号值,到底采用逻辑移位还是算术移位取决于编译器。