按位或运算对两个数的二进制表示的每一位进行逻辑 或操作:
- 规则:两个对应位有一个为1时,结果就为1;只有两个都为0时结果才为0
-
符号:
| -
特点:任何位与1相
或都会变成1,与0相或保持原值
运算过程图示
#include <stdio.h>
void print_binary_5bit(int number) {
for (int i = 4; i >= 0; i--) {
printf("%d", (number >> i) & 1);
}
}
int main() {
unsigned int a = 0b00111; // 十进制 7
unsigned int b = 0b11100; // 十进制 28
printf("按位或运算示例:\n");
printf("a = 7 (二进制: ");
print_binary_5bit(a);
printf(")\n");
printf("b = 28 (二进制: ");
print_binary_5bit(b);
printf(")\n");
printf("\n逐位运算过程:\n");
printf(" ");
print_binary_5bit(a);
printf("\n| ");
print_binary_5bit(b);
printf("\n -----\n ");
print_binary_5bit(a | b);
printf(" (十进制 %d)\n", a | b);
return 0;
}
运行结果:
按位或运算示例:
a = 7 (二进制: 00111)
b = 28 (二进制: 11100)
逐位运算过程:
00111
| 11100
-----
11111 (十进制 31)
实用技巧详解
1. 设置特定位为1(最常用)
#include <stdio.h>
void print_binary_5bit(int number) {
for (int i = 4; i >= 0; i--) {
printf("%d", (number >> i) & 1);
}
}
void set_last_bit_to_one(int number) {
printf("\n将数字 %d 的最末位设置为1:\n", number);
printf("原始数值: ");
print_binary_5bit(number);
printf(" (%d)\n", number);
printf("掩码 1: 00001\n");
printf("按位或运算:\n");
printf(" ");
print_binary_5bit(number);
printf("\n| 00001\n");
printf(" -----\n ");
print_binary_5bit(number | 1);
printf(" (%d)\n", number | 1);
printf("→ 最末位被强制设置为1\n");
}
void set_specific_bits() {
unsigned int flags = 0b10100; // 十进制 20
unsigned int mask = 0b01011; // 十进制 11
printf("\n设置特定位示例:\n");
printf("原始标志位: ");
print_binary_5bit(flags);
printf(" (%d)\n", flags);
printf("设置掩码: ");
print_binary_5bit(mask);
printf(" (要设置的位)\n");
printf("按位或运算:\n");
printf(" ");
print_binary_5bit(flags);
printf("\n| ");
print_binary_5bit(mask);
printf("\n -----\n ");
print_binary_5bit(flags | mask);
printf(" (%d)\n", flags | mask);
printf("→ 掩码中为1的位都被设置为1\n");
}
int main() {
set_last_bit_to_one(10); // 1010 → 1011
set_last_bit_to_one(15); // 1111 → 1111 (不变)
set_specific_bits();
return 0;
}
运行结果:
将数字 10 的最末位设置为1:
原始数值: 01010 (10)
掩码 1: 00001
按位或运算:
01010
| 00001
-----
01011 (11)
→ 最末位被强制设置为1
将数字 15 的最末位设置为1:
原始数值: 01111 (15)
掩码 1: 00001
按位或运算:
01111
| 00001
-----
01111 (15)
→ 最末位被强制设置为1
设置特定位示例:
原始标志位: 10100 (20)
设置掩码: 01011 (要设置的位)
按位或运算:
10100
| 01011
-----
11111 (31)
→ 掩码中为1的位都被设置为1
2. 权限授予系统
#include <stdio.h>
void print_binary_4bit(int number) {
for (int i = 3; i >= 0; i--) {
printf("%d", (number >> i) & 1);
}
}
// 定义权限标志
#define READ_PERM (1 << 0) // 0001 - 读权限
#define WRITE_PERM (1 << 1) // 0010 - 写权限
#define EXEC_PERM (1 << 2) // 0100 - 执行权限
#define ADMIN_PERM (1 << 3) // 1000 - 管理员权限
void grant_permissions(unsigned int current_perm, unsigned int new_perm, const char* user) {
printf("\n为用户 %s 授予权限:\n", user);
printf("当前权限: ");
print_binary_4bit(current_perm);
printf("\n授予权限: ");
print_binary_4bit(new_perm);
printf("\n按位或运算:\n");
printf(" ");
print_binary_4bit(current_perm);
printf("\n| ");
print_binary_4bit(new_perm);
printf("\n ----\n ");
unsigned int result = current_perm | new_perm;
print_binary_4bit(result);
printf(" (新权限)\n");
// 解释权限含义
printf("权限说明: ");
if (result & READ_PERM) printf("读 ");
if (result & WRITE_PERM) printf("写 ");
if (result & EXEC_PERM) printf("执行 ");
if (result & ADMIN_PERM) printf("管理");
printf("\n");
}
int main() {
printf("=== 权限管理系统 ===\n");
// 初始用户只有读权限
unsigned int user_perm = READ_PERM;
grant_permissions(user_perm, WRITE_PERM, "张三");
grant_permissions(user_perm | WRITE_PERM, EXEC_PERM, "张三");
// 管理员一次性授予所有权限
grant_permissions(0, READ_PERM | WRITE_PERM | EXEC_PERM, "管理员");
return 0;
}
运行结果:
=== 权限管理系统 ===
为用户 张三 授予权限:
当前权限: 0001
授予权限: 0010
按位或运算:
0001
| 0010
----
0011 (新权限)
权限说明: 读 写
为用户 张三 授予权限:
当前权限: 0011
授予权限: 0100
按位或运算:
0011
| 0100
----
0111 (新权限)
权限说明: 读 写 执行
为用户 管理员 授予权限:
当前权限: 0000
授予权限: 0111
按位或运算:
0000
| 0111
----
0111 (新权限)
权限说明: 读 写 执行
3. 组合配置标志
#include <stdio.h>
void print_binary_8bit(int number) {
for (int i = 7; i >= 0; i--) {
printf("%d", (number >> i) & 1);
}
}
// 定义配置选项
#define OPTION_A (1 << 0) // 00000001
#define OPTION_B (1 << 1) // 00000010
#define OPTION_C (1 << 2) // 00000100
#define OPTION_D (1 << 3) // 00001000
#define OPTION_E (1 << 4) // 00010000
void build_configuration() {
printf("=== 构建配置选项 ===\n");
unsigned int config = 0;
printf("初始配置: ");
print_binary_8bit(config);
printf("\n\n");
// 逐步添加配置选项
config |= OPTION_A;
printf("添加选项A: ");
print_binary_8bit(config);
printf(" (A | 0)\n");
config |= OPTION_C;
printf("添加选项C: ");
print_binary_8bit(config);
printf(" (当前 | C)\n");
config |= OPTION_E;
printf("添加选项E: ");
print_binary_8bit(config);
printf(" (当前 | E)\n");
// 一次性添加多个选项
config |= (OPTION_B | OPTION_D);
printf("添加B和D: ");
print_binary_8bit(config);
printf(" (当前 | (B | D))\n");
printf("\n最终配置: ");
print_binary_8bit(config);
printf(" (所有选项都已设置)\n");
}
int main() {
build_configuration();
return 0;
}
运行结果:
=== 构建配置选项 ===
初始配置: 00000000
添加选项A: 00000001 (A | 0)
添加选项C: 00000101 (当前 | C)
添加选项E: 00010101 (当前 | E)
添加B和D: 00011111 (当前 | (B | D))
最终配置: 00011111 (所有选项都已设置)
重要注意事项
关于"最末位变成0"的说明
原文中提到"对这个数or 1之后再减一",这实际上不是推荐做法。正确的方法是使用按位与来清除位:
// ❌ 不推荐的做法
int number = 0b1010; // 10
number = (number | 1) - 1; // 变成 1001 (9)
// ✅ 推荐的做法
int number = 0b1010; // 10
number = number & ~1; // 变成 1000 (8) - 清除最末位
总结
按位或运算的核心用途:
-
设置特定位:将指定位强制设置为1
-
flags | mask设置mask中所有为1的位
-
-
权限授予:添加权限而不影响其他权限
- 用户权限 = 当前权限 | 新权限
-
配置组合:逐步构建配置选项
- 配置 = 配置 | 新选项
合并标志:将多个标志合并为一个值
优势:
- 非破坏性:只设置指定位,不影响其他位
- 可组合:可以一次性设置多个位
- 高效:单个操作完成多个设置
按位或运算是设置二进制特定位的首选工具!