2021-11-18-
摘要
操作符
总结
目录
操作符分类
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
算术操作符
+ - * / %
- % 为取余也叫模,它的操作数只能是整数,而其他的操作符的操作数既可以为整数也可以为浮点数。
- 操作数有浮点数时,则进行算术转换进行浮点数运算。
移位操作符
左移操作符 <<
右移操作符 >>
移位操作符对应的是在计算机种的存储形式:补码 (因此移位操作符的操作数仅仅只能是整数。)
左移操作符
对相应的二进制数进行操作。
规则:高位舍去,低位补零。
拓展
左移意味着每一个二进制位的权重会增加1
例如:整形char
假设一个char类型的数据为 6
那么它的二进制表示为
00000110 //6
左移一位后:
00001100 //12
显然任何二进制数都可以表示为:
Σ ∣ ∑ i = 0 n Σ|\sum\limits_{i=0}^{n} Σ∣i=0∑n k * 2i
(k为0或者1)
那么左移一位后,在没有高位溢出的情况下,每一位的权重都增加了1
那么做简单变形:
Σ ∣ ∑ i = 1 n + 1 Σ|\sum\limits_{i=1}^{n+1} Σ∣i=1∑n+1 k * 2i 根据分配律可得: Σ ∣ ∑ i = 0 n Σ|\sum\limits_{i=0}^{n} Σ∣i=0∑n (k * 2i ) * 2
即乘2操作
注意:仅仅是在无溢出的情况下
右移操作符
移位规则:
- 算数右移
左边用符号位填充,右边舍弃。
- 逻辑右移
左边用0填充,右边舍弃。
一般来说我们只针对逻辑右移来讨论:
与左移不同的是,右移操作符在移位的过程中会经常低位非零而被舍弃的情况。
例如:将3右移1位
//逻辑右移
00000011
3 >> 1
00000001
假设 char a = n (n为任何数)
我们准备将 a 右移 k 个位置,可以将其分解为 k 次向右移动一个位置(二进制位)
那么每次分为两种情况
- 最低位为1
- 最低位为0
最低位为1,即先舍去最低位,那么对应到二进制数则可通过 -1操作来完成,然后在移位。
最低位为0,那么则直接移位,不涉及舍弃有效数问题
通过归纳总结:
可以得到 右移操作:
-
如果操作数为奇数 则先 -1 ,再右移。
-
如果为偶数,则直接右移。
通过左移操作的推到同理可得,右移可以是 除以2的操作,即与除以2的结果取整等效。
则右移与整除相同,都是结果取整。
如果是对负数进行移位操作呢?
在数据未溢出的情况下,结论是相同的。
左移 <==> 乘2
右移 <==> 除以2(整除)
思考:如果对-1,进行右移 n 位那么结果如何?
11111111111111111111111111111111
//右移1位
11111111111111111111111111111111
可以看到是未变化的,通过上面得出的结论:
实际上 -1 右移可看作如下步骤:
- -1为奇数,因此先-1得到-2;
- 进行除以2的操作得到 -1
重复上述过程。
**注意:**对于移位运算符,移动负数位是标准为定义的。
位操作符
& 按位与
| 按位或
^ 按位异或
注意:操作数必须为整数
位操作符可以做很多有趣的事情。
对于位操作,我们通常只用进行某一位上对应的二进制值,来获得规律;
异或记住口诀:
相同为0, 相异为1.
可以试想两个个极端情况:
- 一个数二进制全为0
- 两个数二进制相同
其中一个数全为0的情况:
0 ^ 1 -> 1
0 ^ 0 -> 0
非零数的每一个二进制都没变
那么可以轻松得出异或的值还是等于另一个非零的值
两个数完全一样的情况:
0 ^ 0 -> 0
1 ^ 1 -> 0
无论如何,最终二进制位全为0,
即两个相同值异或会得到 0 。
利用这个特性:
思考:如何不适用第三个变量交换两个变量的值。
通常我们会写出如下代码:
void swap(int* num1, int* num2)
{
int tmp = *num1;
*num1 = *num2;
*num2 = tmp;
}
但是这是不符合题意的,但通过位运算,我们可以做到。
void swap(int* n1, int* n2)
{
*n1 = *n1 ^ *n2;
*n2 = *n1 ^ *n2;
*n1 = *n1 ^ *n2;
}
拿a和b来举例:
设未经过任何修改的a,b的值也等于_a, _b的值
int main()
{
int a = 10;
int b = 20;
a = a ^ b; //(1)
b = a ^ b; //(2)
a