跳过正文
P10 位运算
  1. S/
  2. C/C++/
  3. C/
  4. C语言程序设计/

P10 位运算

Li
作者
Li
往前走,别回头!
目录
C 语言程序设计笔记 - 这篇文章属于一个选集。

知识点
#

11.1 位的概念和位运算符简介
#

  • @ 位运算基础图
    • ![[白板/P32 位运算基础.canvas|P32 位运算基础]]

11.1.1 位的概念
#

[!tip] 位的基本概念

  • 1 字节 = 8 个二进制位
  • 最左边的位称为==最高位==,最右边的位称为==最低位==
  • 每个二进制位的值是 01
  • unsigned int 占 4 字节 = 32 个二进制位,最大值 4294967295
类型字节数二进制位数
char18
int432
unsigned int432

11.1.2 位运算符简介
#

位运算符含义运算类型
&按位与二目
|按位或二目
^按位异或二目
~取反单目
<<左移二目
>>右移二目

1. 按位与运算符 &
#

[!tip] 按位与

  • 两个相应位都为 1,结果为 1,否则为 0
  • 公式: 0&0=0; 0&1=0; 1&0=0; 1&1=1
unsigned int tempvalue = 38 & 22;  // 6

// 计算过程(二进制):
// 100110  (38)
// 010110  (22)
// ------  (&)
// 000110  (6)

2. 按位或运算符 |
#

[!tip] 按位或

  • 两个相应位有一个为 1,结果为 1,否则为 0
  • 公式: 0|0=0; 0|1=1; 1|0=1; 1|1=1
unsigned int tempvalue = 38 | 22;  // 54

// 计算过程(二进制):
// 100110  (38)
// 010110  (22)
// ------  (|)
// 110110  (54)

3. 按位异或运算符 ^
#

[!tip] 按位异或

  • 两个相应位相同为 0,不同为 1
  • ==都一样出 0,不一样出 1==
  • 公式: 0^0=0; 0^1=1; 1^0=1; 1^1=0
unsigned int tempvalue = 38 ^ 22;  // 49

// 计算过程(二进制):
// 100110  (38)
// 010110  (22)
// ------  (^)
// 110000  (49)
  • ! 与 1 异或→翻转,与 0 异或→保持不变
// 低4位翻转,高4位保持不变
// 01111010
// 00001111
// --------  (^)
// 01110101

4. 取反运算符 ~
#

[!tip] 取反

  • 单目运算符,0110
unsigned int tempvalue = ~38;  // 4294967257

// 计算过程:
// 00000000,00000000,00000000,00100110  (38)
// ------------------------------------  (~)
// 11111111,11111111,11111111,11011001  (4294967257)

5. 左移运算符 <<
#

[!tip] 左移

  • 二进制位左移若干位,右侧补 0
  • ==每左移一位相当于乘以 2==
unsigned int tempvalue = 15 << 1;  // 30
// 01111 → 11110

unsigned int tempvalue = 15 << 2;  // 60
// 001111 → 111100

6. 右移运算符 >>
#

[!tip] 右移

  • 二进制位右移若干位,超出的位被舍弃,左侧补 0
  • ==每右移一位相当于除以 2==
unsigned int tempvalue = 15 >> 1;  // 7
// 1111 → 0111

unsigned int tempvalue = 15 >> 2;  // 3
// 1111 → 0011

复合赋值运算符
#

复合运算符等价写法
a &= ba = a & b
a |= ba = a | b
a ^= ba = a ^ b
a <<= ba = a << b
a >>= ba = a >> b
int a = 35;
int b = 22;
a &= b;  // a = a & b = 2
// 100011 (35)
// 010110 (22)
// ------ (&)
// 000010 (2)

11.2 位运算的具体应用
#

  • @ 位运算应用图
    • ![[白板/P33 位运算应用.canvas|P33 位运算应用]]

实际应用: 每日任务标记
#

[!tip] 位运算实际用途

  • 用一个 unsigned int 变量记录多达 32 种状态
  • 每个二进制位代表一个任务:0 = 未完成,1 = 已完成
  • 通过按位与判断任务是否完成
  • 通过按位或标记任务完成

核心宏定义
#

#define BIT(n) (1 << (n))  // 实用价值极高

// BIT(0) = 1, BIT(1) = 2, BIT(2) = 4, BIT(3) = 8
// BIT(4) = 16, BIT(5) = 32, BIT(6) = 64, BIT(7) = 128
// BIT(8) = 256, BIT(9) = 512
BIT(n)十进制二进制左移位数
BIT(0)11左移 0 位
BIT(1)210左移 1 位
BIT(2)4100左移 2 位
BIT(3)81000左移 3 位
BIT(4)1610000左移 4 位
BIT(5)32100000左移 5 位
BIT(6)641000000左移 6 位
BIT(7)12810000000左移 7 位

完整实现代码
#

// 定义10个任务的枚举
enum ETask {
    ETask1  = BIT(0),  // 1    = 1
    ETask2  = BIT(1),  // 2    = 10
    ETask3  = BIT(2),  // 4    = 100
    ETask4  = BIT(3),  // 8    = 1000
    ETask5  = BIT(4),  // 16   = 10000
    ETask6  = BIT(5),  // 32   = 100000
    ETask7  = BIT(6),  // 64   = 1000000
    ETask8  = BIT(7),  // 128  = 10000000
    ETask9  = BIT(8),  // 256  = 100000000
    ETask10 = BIT(9)   // 512  = 1000000000
};

unsigned int task = 0;  // 初始化为0,所有任务未完成

// 判断任务7是否完成
if (task & ETask7) {       // 按位与,不为0表示做过
    printf("任务7已经做过了\n");
} else {
    printf("任务7还没做过,现在做任务7\n");
    // 标记任务7完成(按位或)
    task = task | ETask7;  // 将第7位标记为1
}

// 再次判断
if (task & ETask7) {
    printf("任务7已经做过了,可以保存到数据库\n");
}

位运算操作总结
#

操作运算符说明
判断某位是否为 1task & BIT(n)结果不为 0 表示该位为 1
将某位置为 1task |= BIT(n)按位或,标记任务完成
将某位置为 0task &= ~BIT(n)按位与取反,清除标记
翻转某位task ^= BIT(n)按位异或,0↔1 切换
  • ! 一个 unsigned int 变量可记录 32 种状态,节省大量存储空间
Reply by Email
C 语言程序设计笔记 - 这篇文章属于一个选集。

相关文章