C&C++快速入门
7、位运算
1、课程目标
- 掌握所有位运算符的使用
- 理解位运算在底层编程中的应用
- 掌握位掩码和标志位操作
- 学会使用位运算进行性能优化
2、名词解释
| 术语 | 符号 | 说明 |
|---|---|---|
| 按位与 | & | 两位都为1则为1 |
| 按位或 | | | 任一位为1则为1 |
| 按位异或 | ^ | 两位不同则为1 |
| 按位取反 | ~ | 0变1,1变0 |
| 左移 | << | 二进制位左移,低位补0 |
| 右移 | >> | 二进制位右移,高位补符号位或0 |
| 位掩码 | Bitmask | 用于提取或设置特定位的值 |
| 标志位 | Flag | 用一个位表示一个开关状态 |
3、技术原理
3.1、位运算真值表
A B | A&B | A|B | A^B | ~A
0 0 | 0 | 0 | 0 | 1
0 1 | 0 | 1 | 1 | 1
1 0 | 0 | 1 | 1 | 0
1 1 | 1 | 1 | 0 | 0
4、代码实现
1. 基础位运算操作
#include <stdio.h>
void PrintBinary(unsigned int num) {
for (int i = 31; i >= 0; i--) {
printf("%d", (num >> i) & 1);
if (i % 8 == 0) printf(" ");
}
printf("\n");
}
int main() {
printf("=== 位运算基础 ===\n\n");
unsigned int a = 0b11110000; // 240
unsigned int b = 0b10101010; // 170
printf("a = %3d = ", a); PrintBinary(a);
printf("b = %3d = ", b); PrintBinary(b);
printf("\n【位运算结果】\n");
printf("a & b = %3d = ", a & b); PrintBinary(a & b);
printf("a | b = %3d = ", a | b); PrintBinary(a | b);
printf("a ^ b = %3d = ", a ^ b); PrintBinary(a ^ b);
printf("~a = %3d = ", (unsigned char)~a); PrintBinary((unsigned char)~a);
printf("\n【移位运算】\n");
printf("a << 2 = %3d = ", a << 2); PrintBinary(a << 2);
printf("a >> 2 = %3d = ", a >> 2); PrintBinary(a >> 2);
return 0;
}
2. 位操作常用技巧
#include <stdio.h>
// 设置第n位为1
#define SET_BIT(x, n) ((x) |= (1U << (n)))
// 清除第n位(设为0)
#define CLEAR_BIT(x, n) ((x) &= ~(1U << (n)))
// 翻转第n位
#define TOGGLE_BIT(x, n) ((x) ^= (1U << (n)))
// 检查第n位是否为1
#define CHECK_BIT(x, n) (((x) >> (n)) & 1U)
// 获取最低的1位
#define LOWEST_BIT(x) ((x) & (-(x)))
// 清除最低的1位
#define CLEAR_LOWEST(x) ((x) & ((x) - 1))
int main() {
printf("=== 位操作技巧 ===\n\n");
unsigned int flags = 0;
// 设置位
printf("【设置位】\n");
SET_BIT(flags, 0); // 设置第0位
printf("设置第0位后: 0x%02X\n", flags);
SET_BIT(flags, 3); // 设置第3位
printf("设置第3位后: 0x%02X\n", flags);
// 检查位
printf("\n【检查位】\n");
printf("第0位: %d\n", CHECK_BIT(flags, 0));
printf("第1位: %d\n", CHECK_BIT(flags, 1));
printf("第3位: %d\n", CHECK_BIT(flags, 3));
// 清除位
printf("\n【清除位】\n");
CLEAR_BIT(flags, 0);
printf("清除第0位后: 0x%02X\n", flags);
// 翻转位
printf("\n【翻转位】\n");
TOGGLE_BIT(flags, 3);
printf("翻转第3位后: 0x%02X\n", flags);
TOGGLE_BIT(flags, 3);
printf("再次翻转后: 0x%02X\n", flags);
// 特殊技巧
printf("\n【特殊技巧】\n");
unsigned int x = 0b10110100; // 180
printf("x = %d (0b10110100)\n", x);
printf("最低1位: %d\n", LOWEST_BIT(x));
printf("清除最低1位后: %d\n", CLEAR_LOWEST(x));
return 0;
}
3. Windows权限标志位操作
#include <stdio.h>
#include <windows.h>
void PrintFileAccess(DWORD access) {
printf("访问权限 (0x%08lX):\n", access);
if (access & GENERIC_READ) printf(" - 通用读取\n");
if (access & GENERIC_WRITE) printf(" - 通用写入\n");
if (access & GENERIC_EXECUTE) printf(" - 通用执行\n");
if (access & GENERIC_ALL) printf(" - 完全控制\n");
}
void PrintMemoryProtection(DWORD protect) {
printf("内存保护 (0x%02lX):\n", protect);
switch (protect & 0xFF) {
case PAGE_NOACCESS: printf(" 禁止访问\n"); break;
case PAGE_READONLY: printf(" 只读\n"); break;
case PAGE_READWRITE: printf(" 读写\n"); break;
case PAGE_EXECUTE: printf(" 执行\n"); break;
case PAGE_EXECUTE_READ: printf(" 执行+读\n"); break;
case PAGE_EXECUTE_READWRITE: printf(" 执行+读写\n"); break;
}
if (protect & PAGE_GUARD) printf(" + 守护页\n");
if (protect & PAGE_NOCACHE) printf(" + 禁止缓存\n");
}
int main() {
printf("=== Windows标志位 ===\n\n");
// 文件访问权限组合
DWORD access = GENERIC_READ | GENERIC_WRITE;
PrintFileAccess(access);
// 内存保护属性
printf("\n");
PrintMemoryProtection(PAGE_EXECUTE_READWRITE | PAGE_GUARD);
// 进程创建标志
printf("\n【进程创建标志】\n");
DWORD createFlags = CREATE_SUSPENDED | CREATE_NEW_CONSOLE;
printf("标志值: 0x%08lX\n", createFlags);
if (createFlags & CREATE_SUSPENDED) printf(" - 挂起创建\n");
if (createFlags & CREATE_NEW_CONSOLE) printf(" - 新控制台\n");
return 0;
}
4. 位运算实用算法
#include <stdio.h>
// 计算1的个数(Brian Kernighan算法)
int CountBits(unsigned int n) {
int count = 0;
while (n) {
n &= (n - 1); // 清除最低的1位
count++;
}
return count;
}
// 判断是否为2的幂
int IsPowerOfTwo(unsigned int n) {
return n && !(n & (n - 1));
}
// 向上取整到2的幂
unsigned int RoundUpToPowerOfTwo(unsigned int n) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
// 交换两个数(不用临时变量)
void SwapXOR(int* a, int* b) {
if (a != b) { // 必须检查,否则会出错
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
}
// 取绝对值(无分支)
int Abs(int n) {
int mask = n >> 31; // 全0或全1
return (n ^ mask) - mask;
}
int main() {
printf("=== 位运算算法 ===\n\n");
// 计算1的个数
printf("【计算1的个数】\n");
printf("255的1位数: %d\n", CountBits(255));
printf("128的1位数: %d\n", CountBits(128));
// 判断2的幂
printf("\n【判断2的幂】\n");
printf("16是2的幂: %s\n", IsPowerOfTwo(16) ? "是" : "否");
printf("15是2的幂: %s\n", IsPowerOfTwo(15) ? "是" : "否");
// 向上取整
printf("\n【向上取整到2的幂】\n");
printf("100 -> %u\n", RoundUpToPowerOfTwo(100));
printf("1000 -> %u\n", RoundUpToPowerOfTwo(1000));
// 交换
printf("\n【XOR交换】\n");
int x = 10, y = 20;
printf("交换前: x=%d, y=%d\n", x, y);
SwapXOR(&x, &y);
printf("交换后: x=%d, y=%d\n", x, y);
// 绝对值
printf("\n【无分支绝对值】\n");
printf("|42| = %d\n", Abs(42));
printf("|-42| = %d\n", Abs(-42));
return 0;
}
5、课后作业
5.1、作业1:实现位字段结构
使用位运算实现一个IP地址解析器:
void ParseIPv4(DWORD ipAddr);
// 输入: 0xC0A80001
// 输出: 192.168.0.1
5.2、作业2:权限管理系统
实现一个简单的权限管理系统,支持添加、删除、检查权限。
5.3、作业3:简单加密
使用XOR实现简单的数据加密解密(同一密钥加密两次还原)。