C 基础(15) - 位操作

在 C 语言中,位操作(Bitwise Operation)是直接对内存中的二进制位进行处理的运算。它不需要复杂的数学计算,而是通过移动和翻转比特位来工作。

位操作在嵌入式开发、底层驱动、网络协议解析以及算法优化中非常核心,因为它执行效率极高 且能极致节省内存

1. 六大基础位运算符

C 语言提供了 6 种位运算符,操作数必须是整型(int, char, short, long 等)或字符型。

运算符 名称 规则 典型用途
& 按位与 两位均为 1,结果才为 1 清零、保留指定位、判断奇偶
| 按位或 只要有一位为 1,结果为 1 最核心的用途就是**"置位"**
^ 按位异或 两位不同为 1,相同为 0 翻转特定位、无临时变量交换数值
~ 按位取反 0 变 1,1 变 0 构造掩码、取反
<< 左移 二进制位向左移动,低位补 0 乘以 2 的 n 次方(快速乘法)
>> 右移 二进制位向右移动,高位补符号位或 0 除以 2 的 n 次方(快速除法)

2. 核心运算规则详解

按位与 (&)
  • 规则1 & 1 = 1,其余情况均为 0
  • 应用
    • 清零a & 0 结果为 0。
    • 取指定位 :例如 a & 0xFF 可以保留 a 的最低 8 位,将高位清零。
    • 判断奇偶if (n & 1),如果结果为 1 则是奇数,为 0 则是偶数(因为奇数的二进制最后一位一定是 1)。
按位或 (|)
  • 规则0 | 0 = 0,其余情况均为 1
  • 应用 :常用于置位 (Set Bit)。例如,想将变量 a 的第 3 位置为 1,可以使用 a | (1 << 3),其他位保持不变。
按位异或 (^)
  • 规则:相同为 0,不同为 1。

  • 特性

    • 任何数异或自身等于 0 (a ^ a = 0)。
    • 任何数异或 0 等于其本身 (a ^ 0 = a)。
  • 经典算法不使用临时变量交换两个整数

    复制代码
    int x = 10, y = 20;
    x = x ^ y;
    y = x ^ y; // 此时 y 变为 10
    x = x ^ y; // 此时 x 变为 20
移位运算 (<<>>)
  • 左移 (<<)a << n 相当于 a * 2^n。高位丢弃,低位补 0。
  • 右移 (>>)a >> n 相当于 a / 2^n(向下取整)。
    • 逻辑右移:高位补 0(通常用于无符号数)。
    • 算术右移:高位补符号位(0 或 1),以保持负数的符号(通常用于有符号数)。

3. 进阶:位段 (Bit-fields)

如果你需要在结构体中极致地节省空间(例如在嵌入式系统中),可以使用位段。它允许你指定一个成员占用多少个二进制位。

复制代码
struct Flags {
    unsigned int enable : 1;  // 只占 1 位
    unsigned int mode   : 2;  // 占 2 位,可表示 0-3
    unsigned int error  : 1;  // 只占 1 位
}; // 总共只占用 4 字节(一个 int 的大小),而不是 3 个 int

注意 :位段虽然节省空间,但可移植性较差(不同编译器对位的排列顺序可能不同),且不能对位段成员取地址(&)。

4. 常见误区与"坑"

在使用位操作时,有几个非常容易出错的点,请务必注意:

  1. 优先级陷阱

    • 比较运算符 == 的优先级 高于 按位与 &
    • 错误写法if (flags & 0x01 == 1)。这会被解析为 flags & (0x01 == 1),导致逻辑错误。
    • 正确写法if ((flags & 0x01) == 1),务必加括号。
  2. 逻辑运算符与位运算符混淆

    • & 是按位与,&& 是逻辑与。
    • a & b 是对每一位进行运算,结果可能非 0 但不一定是 1;a && b 的结果只能是 0 或 1。
  3. 移位的安全边界

    • 负数移位:对负数进行右移,结果依赖于编译器实现(通常是算术右移),建议对无符号数进行移位操作以保证跨平台一致性。
    • 溢出:左移时如果移出的位包含有效数据(特别是符号位),会导致未定义行为或数据错误。
    • 移位数量 :移位的位数不能大于或等于数据类型的宽度(例如 int 是 32 位,左移 32 位是未定义行为)。
  4. 补码理解

    • 计算机内部数值一律用补码 存储。进行按位取反 ~ 操作时,要考虑到符号位的变化。例如 ~0 的结果是 -1(全 1 的补码)。

位操作是 C 语言贴近硬件特性的体现,熟练掌握它能让你写出更高效、更底层的代码。

相关推荐
念恒123062 小时前
进程控制---进程程序替换
linux·c语言
三品吉他手会点灯2 小时前
STM32 VSCode 开发-C语言程序运行后,终端中文乱码
c语言·ide·笔记·vscode·stm32·学习·编辑器
彷徨而立2 小时前
【C/C++】在头文件中定义全局变量的方法
c语言·开发语言·c++
我不是懒洋洋2 小时前
手写一个跳表:从原理到Redis级实现
c语言
小龙报3 小时前
【数据结构与算法】一文拿捏链式二叉树:遍历 + 统计 + 层序 + 完全树
java·c语言·开发语言·c++·人工智能·语言模型·visual studio
做cv的小昊3 小时前
【TJU】研究生应用统计学课程笔记(5)——第二章 参数估计(2.3 C-R不等式)
c语言·笔记·线性代数·机器学习·数学建模·r语言·概率论
孬甭_3 小时前
自定义类型:联合体与枚举
c语言
Hello.Reader3 小时前
Windows C 盘空间告急?用 PowerShell 写一个安全可控的清理脚本
c语言·windows·安全
三品吉他手会点灯3 小时前
C语言学习笔记 - 17.C编程预备计算机专业知识 - 数据类型
c语言·笔记·学习