当前位置: 首页 > news >正文

C++位运算常见操作

一些位运算的常见操作,整理如下:

注意:
位运算操作符的优先级都非常低,尽量记得加括号。

  1. 给第n位(从右边开始数,初始位置0)值置1
int set_bit(int x, int n){ return x |= (1 << n); }
  1. 清除第n位(从右边开始数,初始位置0)
int clear_bit(int x, int n){ return x &= ~ (1 << n); }
  1. 得到第n位(从右边开始数,初始位置0)
bool get_bit(int x, int n){ return x & (1 << n); }

注意:int数字的第n位和string数字的第n位不一样!
int数字 (例如 011100110110001) 的第n位是从右往左数,
string数字 (例如"011100110110001")的第n位通常是从左往右数。

  1. a ^ b (异或)是不进位加法,即 a ^ b 相加之后该进位的地方不进位的结果。 a & b 就是a 和 b 里都是1的那些位置。
    一个例子如下:

不用+完成加法的算法:

int aplusb(int a, int b) { while (b) { int a1 = a ^ b; int b1 = (a & b) << 1; a = a1; b = b1; } return a; }

以a=3 (0011), b=5(0101)为例。
a = 0011 => 0110 => 0100 => 0000 =>1000 (return) //未进位加法和
b = 0101 => 0010 =>0100 => 1000 =>0000 //进位

递归版本如下:

int aplusb(int a, int b) { if (a == 0) return b; if (b == 0) return a; return aplusb((a & b) << 1, a ^ b); }
  1. 消去二进制中最右侧的那个1:x & (x - 1)
    一些例子如下:

检查n是否为2的幂次位:

bool checkPowerOf2(int n) { return n > 0 && (n & (n - 1)) == 0; }

计算一个32位整数有多少个1

int countOnes(int num) { int count = 0; while (num) { count++; num &= num - 1; } return count; }

计算a要反转多少位变成b

int bitSwapRequired(int a, int b) { int c = a ^ b; int count = 0; while (c) { count++; c &= c - 1; } return count; }
  1. x & (-x) 是x的最右边一个1的位置对应的数 (注意x&(x-1)是将其该位消去)。
    如12 & (-12) 返回4。8 & (-8) 返回8。这个技巧是线段树(Binary Index Tree)算法里面的核心技巧(见Lowbit(x))。

  2. 取反操作~
    正整数的按位取反是其本身+1的负数
    A = (1)10 = (00000000000000000000000000000001)2
    ~A = ~ (1)10 = (11111111111111111111111111111110)2 = (-2)10

负整数的按位取反是其本身+1的绝对值
零的按位取反是 -1

  1. 基于union的bitmap的操作。
typedef union { int all; struct { int flag0 : 1; //bit 0 int flag1 : 1; //bit 1 int flag2 : 1; //bit 2 ... int flag15 : 1; //bit 15 int rsvd : 16; //bit 16-31 } bits; }cntl_t; #define BIT(x) 1<<((n)) cntl_t cntl;

对flag2的操作如下:

#define clear_flag2() (cntl.bits.all &= ~BIT(2)) #define set_flag2() (cntl.bits.all |= BIT(2)) #define get_flag2() (cntl.bits.flag2)

也可以直接对flag进行读写操作。比如说:

cntl.bibts.flag2 = 3;

下面这个链接对C/C++ bit field的操作说的非常清楚,是一个非常好的链接。
https://aticleworld.com/bit-field-in-c/

  1. Gray Code 的生成一种方法是基于i ^ (i << 1)。

  2. 负数的移位很重要!
    C/C++中左移是逻辑移位,右端补0,所以负数左移,有可能变成正数
    C/C++中右移是算数移位,左端补齐最高位的符号位。
    负数右移,肯定还是负数
    引用https://blog.csdn.net/e3399/article/details/7526230的例子

/********************************************************************** * Compiler: GCC ************************************************************************/ #include <stdio.h> int main(int argc, char **argv) { int i = 0x8000000f; //这里的0x8000000f为int型数据的补码形式 int j = i >> 3; //右移是算术移位,左端补齐的是符号位 int k = i << 1; //左移是逻辑移位,右端补0 printf("%d %x\n", i, i); printf("%d %x\n", j, j); printf("%d %x\n", k, k); i = -9; printf("%d %x\n", i, i); i = 0xfffffff7; j = i >> 3; k = i << 1; printf("%d %x\n", i, i); printf("%d %x\n", j, j); printf("%d %x\n", k, k); return 0; }

Output:
-2147483633 8000000f
-268435455 f0000001
30 1e
-9 fffffff7
-9 fffffff7
-2 fffffffe
-18 ffffffee

注意:
-9 << 1 = -18, 并不是乘2这么简单。
-9的补码是0xffffffff7,<<1后变成0xffffffEE,即1111…1110 1110
此即-18的补码。

  1. 用16进制的形式对数据进行赋值,这16进制的数代表的是补码
    补码:负数的补码是在其原码的基础上,符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
    [+1] = [00000001]原 = [00000001]反 = [00000001]补
    [-1] = [10000001]原 = [11111110]反 = [11111111]补
i = 0xfffffff7; //0xfffffff7是补码,而不是原码,故i = -9 printf("%d %x\n", i, i); i = -9; printf("%d %x\n", i, i); //故两个printf输出结果相同

12)取模运算可以用:
a % b = a - (a / b) * b
如果b为2的n次方,可用
a % b = a & (b - 1)

  1. 2147483648实际上是存的-2147483648?
    因为
    2147483647 = 01111111 11111111 11111111 11111111
    -2147483647表示为(2的补码)
    10000000 00000000 00000000 00000001
    -2147483648(2的补码)还可以比-2147483647少1,所以是
    10000000 00000000 00000000 00000000
    另外,实际上补码的补码就是原码(数的原始表示)
    所以10000000 00000000 00000000 00000000 的补码是
    11111111 11111111 11111111 11111111 + 1,第一个1是负号,所以
    1111111 11111111 11111111 11111111 + 1 = 10000000 00000000 00000000 00000000=2147483648,这里第一个1是实际数字。加上负号,即-2147483648。
    另外,11111111,11111111,11111111,11111111看起来很大,实际上是存的-1。

  2. 位运算如果和硬件结合起来会更快。
    比如说ARM芯片支持__clz()内置函数,返回某无符号整数的前置0的个数。

Syntax: unsigned char __clz(unsigned int val) Return value The __clz intrinsic returns the number of leading zeros in val.

有了__clz()函数,我们就可以定义下面的MSB(x)宏来返回MSB比特(即从高到低第一个1)的位置。

#define MSB(x) (31- __clz((unsigned int)x))

注意这里默认一个unsigned int占4个字节。
用下面的循环我们可以快速遍历一个unsigned int (即下面的bitmap)的1,注意while里面的操作次数就是bitmap里面的1比特的个数。

unsigned int bitmap = 0x1234; while (bitmap) { int pos = MSB(bitmap); //do something bitmap &= ~(0x1<< pos); }
  1. 如果n是2^k,那么x % n = x & (n - 1),显然后者更快。
    比如说33 % 8 = 33 & 7 = 1, 37 % 8 = 37 & 7 = 5

  2. Round up to the next highest power of 2
    from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2

unsignedintv;// compute the next highest power of 2 of 32-bit vv--;v|=v>>1;v|=v>>2;v|=v>>4;v|=v>>8;v|=v>>16;v++;

    从一个整数中提取 [start, start + width) bit field,意思是:
    从 bit start 开始
    一共提取 width 个 bits
    bit 编号从最低位 0 开始
    核心公式:
    field = (value >> start) & mask;
    其中:
    mask = (1U << width) - 1U;

    Example:
    value = 1101 0110
    提取:
    [start, start + width) = [2, 6)
    也就是 bit [5:2]:
    value = 11 0101 10
    ↑↑↑↑
    bits 5:2 = 0101
    代码:
    uint32_t value = 0xD6U; /* 1101 0110 */
    unsigned start = 2;
    unsigned width = 4;
    uint32_t mask = (1U << width) - 1U;
    uint32_t field = (value >> start) & mask;

    value >> 2 = 0b1101 0110 >> 2 = 0b0011 0101
    mask = 0b00001111
    field == (value >> start) & mask = 0b0101 = 5

    http://www.jsqmd.com/news/1284171/

    相关文章:

  1. 2026年度重庆分布式光伏专业生产厂商综合解析与选择指南 - 装修教育财税推荐2026
  2. AI 时代,零售商超如何用多模态数据“看见“每一排货架?
  3. Suno AI采样拼接技术详解:从音频特征提取到智能音乐生成实战
  4. # HarmonyOS ArkTS 记忆翻牌游戏深度解析 —— Fisher-Yates 洗牌与翻牌匹配机制
  5. 2026 年更新:肥城知名的旧地面翻新施工施工队哪家可靠,别再浪费钱!旧地面翻新避坑指南-兴迈地坪施工 - 鉴选官
  6. 大鹏新区企业搬家上门打包 省心高效一站式搬迁服务全指南 - 品牌优推
  7. 终极指南:5分钟掌握ModTheSpire游戏模组加载器完整安装与使用教程
  8. 2026年杭州中考冲刺班机构大揭秘! - 品牌排行榜
  9. 分治法在大数据计算中的并行化应用探索7
  10. 3D打印机喷头加热器故障诊断与更换实战指南
  11. 2026年手机维修哪家强?高性价比选择看这里
  12. 【监控实战】Spring Boot 3.3 + AI Agent × Prometheus:让AI自动发现故障并告警,平均故障响应从30分钟压到2分钟
  13. 字符串匹配算法的演变:从BF到KMP再到BM
  14. NBM5100A与PIC18LF47K42在低功耗物联网设计中的协同应用
  15. 2026年兰州早强灌浆料制造商怎么挑选才稳妥? - 品牌优推
  16. 2026 年现阶段崇礼诚信的阻燃保温板定做厂家找哪家,别再乱选!这板子如何帮你省下高昂的消防成本?-朗诺挤塑板 - 领域鉴赏官
  17. 找新疆味道好的无添加干果干果店 乌鲁木齐本地值得信赖老牌门店 - 品牌优推
  18. 2026年上海中古车门店怎么选?看这家老牌俱乐部如何圆梦 - 品牌优推
  19. 2026 年当下,丹凤有实力的高铁施工物料运输车源头厂家哪家可靠,这台不起眼的“工地巨无霸”,凭啥撑起高铁建设的关键补给线? - 企业信息推荐【官方】
  20. 上海有COSCO和OOCL合作货代公司分享:航线覆盖广,舱位稳定有保障 - 2027品牌AI展
  21. 华为OD机试真题解析:滑动窗口与哈希表在异常打卡检测中的应用
  22. Arduino调试宏工具箱:告别Serial.print,实现高效结构化日志
  23. Unity Shader实现2D游戏天空日夜循环:从渐变到星辰的动态环境
  24. 如何3步完成Palworld存档编辑:免费开源工具终极指南
  25. 开源AI模型部署实践:从技术选型到企业级应用
  26. 汽车维修保养公司帮我推荐:2026年北京车主怎么选? - 品牌优推
  27. 2026年北京豆包广告推广服务商服务详解及选购指南 - 品牌优推
  28. AI工具提升学术论文写作效率的实践指南
  29. 北京大量废甲醇机构部业务对接与合规处置指南 - 品牌优推
  30. 2026年牌楼施工专业团队解析:工艺、选型与行业前瞻 - 装修教育财税推荐2026