算术运算符
2. 乘法类运算符 *
/
%
2.1 乘法 *
*
是一个二元运算符,用于计算乘法。
2.2 除法 /
整数除以整数,结果为整数,向零取整:
cint a = 6 / 3; // a = 2 int b = 5 / 3; // b = 1 int c = -6 / 2; // c = -3 int d = -5 / 2; // d = -2
1
2
3
4
NOTE
以下内容十分杂乱,且存在错误,有待整理。
2. 位操作
类型要求
只能使用整型数据进行位操作。
2.1 位操作的种类
下面的例子使用无符号 8 位整数进行演示:
按位与 (&):对应位都为
1
时,结果才为1
:C(10011010) & (10110110) // 表达式 10010010 // 结果值
1
2当然 C 中有一个按位与和赋值结合的运算符:
&=
按位或 (|):对应位只要有一个为
1
或都为1
,结果就为1
:C(10011010) | (10110110) // 表达式 10111110 // 结果值
1
2当然 C 中也有一个按位或和赋值结合的运算符:
|=
按位异或 (^):对应位不同时,结果为
1
:C(10011010) ^ (10110110) // 表达式 00101100 // 结果值
1
2当然 C 中也有一个按位异或和赋值结合的运算符:
^=
按位取反 (~):
1
变0
,0
变1
:C~(10011010) // 表达式 01100101 // 结果值
1
2按位左移 (<<):
C(10011010) << 2 // 表达式 01101000 // 结果值
1
2当然 C 中也有一个按位左移和赋值结合的运算符:
<<=
按位右移 (>>):
C(10011010) >> 2 // 表达式,有符号 00100110 // 在某些实现中的结果 11100110 // 在另一些实现中的结果
1
2
3在不同实现中,对有符号数的右移操作,其左端填补数可以为
1
也可以为0
。大多数实现中,左端填补数和原符号位相同,确保正负不变。C(10011010) >> 2 // 表达式,无符号 00100110 // 结果值
1
2当然 C 中也有一个按位右移和赋值结合的运算符:
>>=
2.2 位操作的应用
注:在之后的实际项目里,尤其是对 硬件 开发上,位操作会经常用到 在下面的示例中,使用无符号整数来演示,即
unsigned int
类型,默认你们已经引入stdint.h
头文件:
#include <stdint.h>
或者,也可以使用 typedef
定义一些无符号整数类型,如下:
typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
typedef unsigned short int uint16_t;
typedef unsigned char uint8_t;
2
3
4
示例中的 二进制字面量 只有 8 位,这其实没什么问题,因为二进制位数是由类型决定的,而不是字面量的位数,因此,**字面量位数 ** 可以比 该字面量类型位数 少,也可以比 该字面量类型位数 多。但需要注意的是,二进制存储是 从右往左 的,因此,如果 字面量位数 比 该字面量类型的位数 多,那么,字面量左边的位会被丢弃,如下:
uint32_t flag = 0b1111111100000000000000000000000000000000;
// 40位的字面量,如果 int 为 32 位,那么 flag 只能存储 32 个二进制位
// 可能造成如下结果:
// flag = 0b00000000000000000000000000000000(flag 最左的 8 位被丢弃)
2
3
4
5
若是字面量位数比该字面量类型的位数少,那么,字面量左边的位会被补零。
掩码 ( MASK )
定义:掩码是一个 二进制数,用于 屏蔽 另一个二进制数的特定位
可以这样类比:掩码就像一个 滤网 ,只有掩码中的 1 是孔,把 flag 的对应位置给透出来,其余位置被 0 给堵上
下面举个简单的例子:
C//typedef unsigned char uint8_t; uint8_t flag = 0b10101010; //定义 MASK,0 号位为 1,其余位为 0 uint8_t mask = 0b00000010; //掩码操作 flag = flag & mask; //此时 flag = 0b00000010
1
2
3
4
5
6
7
8
9
打开位 ( SET )
定义:打开位,就是将特定位设置为
1
,同时保持其它位不变使用
|
运算符和掩码,翻译成人话就是:任何位和1
组合,结果都是1
;任何位和0
组合,结果都是该位本身以上一节的 mask(只有
1
号位为 1)为例:Cuint8_t flag = 0b10101001; flag |= mask; //此时 flag = 0b10101011
1
2根据 mask 中为
1
的位, flag 中对应位设置为1
,其余位不变
清空位 ( CLEAR )
定义:清空位,就是将特定位设置为
0
,同时保持其它位不变使用
&
和~
运算符与掩码,看代码:以上一节的 mask(只有
1
号位为 1)为例:Cuint8_t flag = 0b10101011; flag &= ~mask; //此时 flag = 0b10101001
1
2根据 mask 中为
1
的位, flag 中对应位设置为0
,其余位不变
切换位 ( TOGGLE )
定义:切换位,就是将特定位取反,同时保持其它位不变
使用
^
运算符和掩码,即:任何位和1
组合,结果都是该位取反;任何位和0
组合,结果都是该位本身以新的 mask(
0b11110000
)为例:Cuint8_t flag = 0b10101011; flag ^= mask; //此时 flag = 0b01011011
1
2根据 mask 中为
1
的位, flag 中对应位切换,其余位不变
读取位 ( READ )
定义:读取位,就是只读取特定位的值
使用
&
运算符和掩码,代码如下:以上一节的 mask(只有
1
号位为 1)为例:Cuint8_t flag = 0b10101011; if ((flag & mask) == mask) { printf("1 号位为 1。"); }
1
2
3
4根据 mask 中为
1
的位,在 flag 中只读对应。