二进制位运算#
(注:以下例子如无特别标注均为 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 )操作。
如何定义 位段 ?#
与结构体类似的定义方式
1 | struct name |
如此定义,f1占用1个二进制位,f2占用2个二进制位,f3占用4个二进制位,以上位段共需占用1字节。
定义了结构后便可定义位段结构类型的变量,如
struct packed_d x,y
如何使用?#
与结构体类似 x.f1=1; x.f2=3;
[!warning]
所赋值需考虑所占用的二进制位数,若超出则取低位舍高位
注意#
位段成员需位 unsigned 型
可定义无名位段 如下所示,无名位段起占位作用。若无名位段宽度为0,则表明下一位段从一个新字节开始存放 如下所示,该位段结构占2字节。
1
2
3
4
5
6
7
8
9struct
{
unsigned short f1:1;
unsigned short f2:2;
unsigned short :1;
unsigned short f3:1;
unsigned short :0;
unsigned short f4:3;
}位段成员所占二进制位数不超过编译器字长
位段不能说明为数组,也不可用指针指向位段成员。
不可用
sizeof()
求位段成员大小定义位段结构类型时,可包含非位段成员
结构体类型变量的位段成员可在一般表达式中被引用,并自动转换为对应整数。