C++ 位运算(Bitwise Operations)全解
C 位运算Bitwise Operations全解主题要点示例位运算符^~为什么要学位运算速度快直接映射到 CPU 指令代码简洁掩码常常减少 loops低级硬件控制配合寄存器、IO、图像处理下面把所有常见的位运算讲得“通俗易懂”并配示例代码让你一下子能看到效果。1. 位运算符概览运算符含义说明按位与对应位都为 1 时结果为 1用来掩码取某些位按位或至少有一个 1 时结果为 1^按位异或两个对应位不相同则为 1用来翻转、计数奇偶位~按位取反每个位变成 1 - 该位取反后再与其他号做运算左移所有位往左移动低位补 0乘以 2 的幂右移所有位往右移动对 unsigned 高位补 0对 signed 高位按符号位补取反乘 2 的幂或除以 2 的幂注意位数是以二进制为单位。C 本身并不关心数是十进制还是十六进制二进制视角才是正确解释位运算的方式。2. 基础示例假设我们在 8 位设备中用 1 字节uint8_t存放 8 个状态位flags。位索引从右到左含义十六进制掩码0P10x011P20x022P30x043P40x084..7预留0xF0#include cstdint #include cstdio #include iostream using namespace std; int main() { uint8_t status 0x00; // 所有位 0 // 设置 P1、P3 位 status | 0x01; // P1 1 status | 0x04; // P3 1 printf(status after set: 0x%02X\n, status); // 0x05 // 查询 P3 是否为 1 bool p3_on status 0x04; // 非零则为 true cout P3 is (p3_on ? ON : OFF) endl; // 清除 P1 位 status ~0x01; // 把 P1 的掩码取反后与 status 做 把该位改为 0 printf(status after clear: 0x%02X\n, status); // 0x04 // 翻转 P3 位 status ^ 0x04; printf(status after toggle: 0x%02X\n, status); // 0x00 }输出示例status after set: 0x05 P3 is ON status after clear: 0x04 status after toggle: 0x00你会发现与() 用来提取掩码对应位或(|) 用来打开掩码对应位异或(^) 用来翻转掩码对应位取反(~) 与与() 结合可以关闭某位。3. 数位与掩码Mask掩码是位运算中最重要的概念。3.1 生成掩码auto getMask [](int pos){ // pos 从 0 开始 return 1u pos; // 1 向左位移 pos 位 };使用getMask(3)得到0x08(00001000)。3.2 提取某段连续位假设我们有 32 位整数其中 12–19 位置储存某段信息8 位。掩码可以这样创建uint32_t mask ((1u 8) - 1) 12; // 0x000FF000提取uint32_t value (num mask) 12; // 右移取值示例把地址中的区段拆开uint32_t address 0xABCD1234; uint8_t high (address 24) 0xFF; // 高 8 位 uint8_t mid (address 12) 0x0FFF; // 12 位 uint16_t low address 0xFFF; // 12 位 printf(high0x%02X mid0x%03X low0x%03X\n, high, mid, low);4. 位移运算Shift运算符含义示例说明x n左移 n 位相当于2ⁿint x 3 2;→x 12低位补 0注意溢出x n右移 n 位int y 12 2;→y 3对 unsigned 高位补 0对 signed 右移时会补符号位算术右移Tip对无符号uint8_t、uint32_t右移是安全的对有符号int右移要注意符号位补导致负数时不一定得到你想的结果。4.1 乘除 2 的幂x n等价于x * (1 n)x n等价于x / (1 n)对无符号整数int main() { int a 7; int b a 3; // 7 * 8 56 int c a 1; // 7 / 2 3 (整数除法) printf(%d 3 %d, %d 1 %d\n, a, b, a, c); }5. 常见技巧 典型用例目的C 代码说明检查偶数/奇数if (x 1) odd; else even;最右位LSB即1表示奇数快速求 2 的最大幂次int pow2 1 (sizeof(int)*8 - __builtin_clz(x));GCC/Clang 内建函数计数前导零翻转整数int rev ~x;相当于 XOR 0xFFFFFFFF快速乘 / 除 10tmp ((x * 0x5555) 1) (x * 0xAAAA); /* 近似 */不是精确值但整数运算很快缓冲区掩码u32 flags 0;// 0: no flagbr flags 0x01U;// 设置brflags ~0x02U;// 清除brif (flags 0x01U) …️ 小心安全~对无符号类型是 1 的补码结果通常是0xFFFFFFFF下的反码。位移超过类型宽度C 标准未定义例如1 32对 32 位类型请避免。有符号右移在不同编译器/CPU 之间可能差异除非知道高位补 0 还是补符号位算术 vs 逻辑移位。6. C 标准库帮助6.1std::bitset如果你需要动态或可读地操作固定长度位字段bitset是一把利器。#include bitset #include iostream int main() { std::bitset8 bs(0); // 8 位 bs.set(0); // 00000001 bs.set(2); // 00000101 std::cout bs \n; // 101 bs.flip(0); // 100 std::cout bs \n; }bitset也可以读取/修改单个位返回位对象甚至可以打印二进制字符串。6.2std::cntl/_builtin_popcount现代编译器提供内建函数来统计 1 位数也叫“population count”int popcnt32(unsigned x) { #if defined(__GNUC__) || defined(__clang__) return __builtin_popcount(x); #elif defined(_MSC_VER) return __popcnt(x); // MSVC 体验 #else // 手写 1 计数 int cnt 0; while (x) { cnt; x x - 1; } return cnt; #endif }x x - 1的技巧是“先把最低位 1 置零”。7. 高级主题可选如果你想进一步“加点料”可以了解以下内容略但想学的你可以自己去找教程方向说明位图压缩仅记录状态减少内存占用例如棋盘、地图SIMD使用诸如 SSE / AVX 的向量位运算一次处理 128/256 位位级哈希 / CRC用位运算实现校验码位指令直接给寄存器BSF,BSR,BLSF等了解二进制位的“最右 1 位”或“最左 1 位”位域struct { unsigned flag : 1; unsigned mode : 3; };用结构体的位域实现紧凑字段书面来说位运算让你把数据压缩到最低位做矩阵运算、视图剪裁、数码逻辑、甚至 AI 的稀疏矩阵都能用到。8. 总结位运算是对整数按位做 AND、OR、XOR、NOT、左/右移。掩码让你可以提取、设置、清除、翻转某一组位。位移与乘除 2 的幂直接相关特别高效。标准库std::bitset、__builtin_popcount让你写得更安全、更可读。注意签名的右移、溢出的未定义行为、搬运位宽限制。只要多练习你的假设比如把整数拆分成数独格、把float的符号位提取出来、把数据打包到 32 位就会发现C 位运算已经变成了你代码中的“快捷工具箱”。祝你玩得开心写出超快、高效又可读的代码
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2552118.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!