5 位运算
二进制位运算
(注:以下例子如无特别标注均为 short
类型)
按位与 "&"
同 1 为 1,否则为 0
也可以理解为 有 0 则 0 or &1 得原值
0&0=0 0&1=0 1&0=0 1&1=1
用途
- 取指定位
- 取
short x
的低 8 位:x & 0x00ff
(0x00ff
为二进制0000 0000 1111 1111
) - 取
short x
的高 8 位:x & 0xff00
(0xff00
为二进制1111 1111 0000 0000
) - 判断
short x
的第 3 位是否为 1 :x& 0x08
(0x08
为二进制0000 1000
)
TIP
取第 x 位即 第 x 位 & 1 其余位 & 0
判断第 x 位是否为 1 即 第 x 位 & 1 其余位 & 0
16 进制中 f
表示 1111
,0
表示 0000
WARNING
二进制位数从右往左数分别是 第 0 位 第 1 位 第 2 位 第 3 位 以此类推
- 将指定位清零
- 将
short x
的低 8 位清零:x & 0xff00
- 将
short x
的高 8 位清零:x & 0x00ff
- 将
short x
的第 8 位清零:x & 0xffef
TIP
清零第 x 位 就让 第 x 位 & 0 其余位 & 1
按位或 "|"
有 1 为 1,否则为 0
0|0=0 0|1=1 1|0=0 1|1=1
用途
将指定位 置 1,其余位不变 如 x = x|0x00ff or x|= 0x00ff
TIP
将第 x 位 置 1,就让 第 x 位 |1
按位异或 "^"
相同为 0,不同为 1
0^0=0 0^1=1 ,1^0=1 1^1=0
用途
某些位取反
- 低字节取反,高字节不变
x = x^0x00ff
- 高字节取反,低字节不变
x = x^0xff00
- 第 0 位和第 4 位取反,其余位不变
x = x^0x0011
TIP
将第 x 位取反,就将第 x 位 ^1
- 低字节取反,高字节不变
变量清零
x = x^x
若
x y
均为整型,则(x^y)^y = x
若
x y
均为整型,可交换变量x = x^y; y = x^y; x= x^y;
按位取反 "~"
~0 == 1, ~1 == 0
只有这个用途了吗?取反后的数和原数有什么关系呢?
我们之前讲了进制与编码,不难发现
按位取反后得到的是这个数的反码,反码 + 1 = 相反数的补码
故可知 一个数按位取反 = 该数的相反数 - 1
左移 "<<"
向左移动 n 位,多余的高位丢弃,低位补 0
例 x<<3
将 x 的二进制位左移 3 位
右移 ">>"
向右移动 n 位,多余的低位丢弃,高位遵循以下规则增补
- 若右移对象为 无符号整数,高位补 0
- 若为 整型 或 字符型 :
- 最高位为 0 时补 0,
- 最高位为 1 时,若编译系统采用 “算数右移
则高位补 1,若编译系统采用 “逻辑右移” , 则高位补 0.” ,
WARNING
在 32 位微软编译系统中,采用 “算术右移” 的形式
位段
大家应该都接触过
bool
型变量,只存储 0 与 1,但是否想过bool
型所占空间是多少呢?答案是 1 字节,即 8 位。
这时候就有人会问了,欸 0 与 1 的存储不是只需要占用 1 位吗,为什么需要用到 8 位呢?
很简单,因为 C 语言对内存的存取大部分情况下使用的是指针,但指针只能精确到字节,无法精确到位。所以 bool 类型的空间占用远超实际占用,只能使用最小字节单位。
怎么解决这个问题呢?C 语言为此提供了位段(bit-field)操作。
如何定义 位段?
与结构体类似的定义方式
struct name {
member_list
};
e.g.struct packed_d {
unsigned short f1 : 1;
unsigned short f2 : 2;
unsigned short f3 : 4;
}
如此定义,f1 占用 1 个二进制位,f2 占用 2 个二进制位,f3 占用 4 个二进制位,以上位段共需占用 1 字节。
定义了结构后便可定义位段结构类型的变量,如 struct packed_d x,y
如何使用?
与结构体类似 x.f1=1; x.f2=3;
WARNING
所赋值需考虑所占用的二进制位数,若超出则取低位舍高位
注意
位段成员需为 unsigned 型
可定义无名位段 如下所示,无名位段起占位作用。若无名位段宽度为 0,则表明下一位段从一个新字节开始存放 如下所示,该位段结构占 2 字节。
Cstruct { unsigned short f1 : 1; unsigned short f2 : 2; unsigned short : 1; unsigned short f3 : 1; unsigned short : 0; unsigned short f4 : 3; }
位段成员所占二进制位数不超过编译器字长
位段不能说明为数组,也不可用指针指向位段成员。
不可用
sizeof()
求位段成员大小定义位段结构类型时,可包含非位段成员
结构体类型变量的位段成员可在一般表达式中被引用,并自动转换为对应整数。