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 语言贴近硬件特性的体现,熟练掌握它能让你写出更高效、更底层的代码。

相关推荐
AI thought17 小时前
【转】C语言中 -> 是什么意思?
c语言·位移运算符·右移赋值·无符号整数·算术右移
qeen8719 小时前
【C++】类与对象之类的默认成员函数(二)
android·c语言·开发语言·c++·笔记·学习
wuminyu1 天前
Java锁机制之park和unpark源码剖析
java·linux·c语言·jvm·c++
asdfg12589631 天前
C 语言中产生伪随机数的标准做法
c语言·开发语言
玖玥拾1 天前
C/C++ 基础笔记(十一)类的进阶
c语言·c++·设计模式·
Soari1 天前
llama.cpp更新(b9553):LLM inference in C/C++,本地和云端实现高性能大模型推理
c语言·c++·llama
2601_961194021 天前
考研资料电子版|去哪找|网盘
java·c语言·c++·python·考研·php
十月的皮皮1 天前
C语言学习笔记202606008- 三角形判断(3种方法)
c语言·笔记·学习
c++之路1 天前
C/C++ 全链路编译工具汇总
c语言·开发语言·c++
凡人叶枫1 天前
Effective C++ 条款02:宁可以编译器替换预处理器
java·linux·c语言·开发语言·c++