【嵌入式linux学习】0_3位运算整理

位运算整理

最近看到了位运算相关的东西,也趁机会复习一下~

特别是操作寄存器的某些位的时候需要熟练使用 主要就是构建掩码,熟练使用几个运算符~

文章目录


1. 将x的某些位取出来

需求 :从无符号整数 x 中,提取从第 p 位开始(向右数)的 n 位字段。

实现原理

  1. 将目标字段移动到最右侧:执行 x >> (p - n + 1)
  2. 构造掩码(Mask):~(~0 << n) 可以生成一个右起 n 位全为 1,其余为 0 的掩码。
  3. 相与提取:利用 & 运算过滤出目标位。
c 复制代码
unsigned int getbits(unsigned int x, int p, int n) {
    return (x >> (p - n + 1)) & ~(~0 << n);
}

2. 将x的某些位 设置为y的某些位

需求 :将 x 中从第 p 位开始的 n 个位,替换为 y 中最右边的 n 位,其余位保持不变。

实现思路

  • 清理现场 :构造一个 x_mask,将 x 的目标区间清零。
  • 对齐数据 :将 y 的低 n 位移动到第 p 位对齐。
  • 合并结果 :使用按位或 | 运算。
c 复制代码
unsigned int setbits(unsigned int x , int p,int n,unsigned int y){
	unsigned int x_mask=(~((~0)<<n))<<(p-n+1);
    unsigned int y_mask=~((~0)<<n)
    return ((~x_mask)&x) | (y<<(p-n+1) &mask);
}

3. 位翻转:invert 函数

需求 :将 x 中从第 p 位开始的 n 位求反(0 变 1,1 变 0)。

编写一个函数 invert(x, p, n),该函数返回对 x 执行下列操作后的结果值:将 x 中从第 p 位开始的 n 个(二进制)位求反(即,1 变成 0,0 变成 1),x 的其余各位保持不变

核心技巧:异或(XOR)

异或运算 ^ 具有如下神奇特性:

  • any ^ 0 = 保持不变
  • any ^ 1 = 翻转
c 复制代码
unsigned int invert(unsigned int x, int p, int n) {
    // 构造掩码:目标区间为 1,其余为 0
    unsigned int mask = (~(~0u << n)) << (p + 1 - n);
    // 利用异或翻转目标位
    return x ^ mask;
}

4. 循环移位:rightrot 函数

需求:实现循环右移,即从右端移出的位不再丢失,而是从左端重新移入。

编写一个函数 rightrot(x, n),该函数返回将 x 循环右移(即从最右端移出的位将从最左端移入)n(二进制)位后所得到的值

实现步骤

  1. 获取位数 :通过 sizeof(unsigned int) * 8 适配不同系统的字长。
  2. 提取掉落位 :获取即将移出的低 n 位,并将其左移到顶端。
  3. 整体右移:将原数正常右移。
  4. 合并:将"掉落位"与"移位结果"进行或运算。
c 复制代码
unsigned int rightrot(unsigned int x, int n) {
    int wordsize = sizeof(unsigned int) * 8;
    n = n % wordsize; // 处理 n 大于字长的情况
    if (n == 0) return x;

    unsigned int dropped_bits = (x & ~(~0u << n)) << (wordsize - n);
    return (x >> n) | dropped_bits;
}

5. x & (x - 1)

经典技巧,它的核心作用是:消除二进制表示中从右往左数的第一位 1

为什么有效?

当我们执行 x - 1 时:

  • 最右侧的 1 变成 0
  • 该位右侧的所有 0 变成 1
  • 该位左侧保持不变。 此时执行 & 运算,原数中最右侧的 1 及其右边部分都会被抵消。

经典应用:统计 1 的个数

相比于逐位遍历 32 次,该算法的效率取决于 1 的个数。

c 复制代码
int count_ones(unsigned int x) {
    int count = 0;
    while (x > 0) {
        x &= (x - 1); // 每次执行都干掉一个 1
        count++;
    }
    return count;
}

总结

位运算的本质是对**掩码(Mask)移位(Shift)**的灵活组合。

一般用~0 进行位置移动,移动后取反 当作掩码

翻转常用^

相关推荐
dllmayday19 小时前
Linux 上用终端连接 WiFi
linux·服务器·windows
努力努力再努力FFF20 小时前
医生对AI辅助诊断感兴趣,作为临床人员该怎么了解和学习?
人工智能·学习
峥无20 小时前
Linux系统编程基石:静态库·动态库·ELF文件·进程地址空间全景图
linux·运维·服务器
用户23678298016821 小时前
从 chmod 755 说起:Unix 文件权限到底是怎么算的?
linux
Strugglingler21 小时前
【systemctl 学习总结】
linux·systemd·systemctl·journalctl·unit file
sakiko_21 小时前
UIKit学习笔记5-使用UITableView制作聊天页面
笔记·学习·swift·uikit
Alice-YUE1 天前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
嵌入式×边缘AI:打怪升级日志1 天前
100ASK-T113 Pro 开发板 Bootloader 完全开发指南
linux·ubuntu·bootloader
北山有鸟1 天前
修改源码法和插件法
嵌入式硬件·学习
richxu202510011 天前
嵌入式学习之路->stm32篇->(14)通用定时器(上)
stm32·单片机·嵌入式硬件·学习