《嵌入式Linux与物联网软件开发——C语言内核深度解析》一2.7 技术升级:用宏定义来完成位运算

简介:

本节书摘来自异步社区《嵌入式Linux与物联网软件开发——C语言内核深度解析》一书中的第2章,第2.7节,作者朱有鹏 , 张先凤,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.7 技术升级:用宏定义来完成位运算

在Linux内核源码中有很多函数,你一层一层地查看进去,会发现其最终实现其实是一些宏构成的。本节举几个用宏实现位运算的例子。

2.7.1 直接用宏来置位

用宏定义将一个32位二进制数x的第n位(从右边起算,也就是bit0算第1位)置位。

显然,这个宏含有两个参数,即x和n,所以其模型为 #define SET_BIT_N(x,n) xxx。

对其某一位置位,我们可以将该位和1相或,其他位和0相或即可,所以得到x | (1<<(n-1))。

所以该宏为#define SET_BIT_N(x,n) ((x) | (1<<((n)-1)))。

2.7.2 直接用宏来复位

用宏定义将一个32位二进制数x的第n位(右边起算,也就是bit0算第1位)清零。

显然,这个宏含有两个参数,即x和n,所以其模型为 #define CLR_BIT_N(x,n) xxx。

对其某一位清零,我们可以将该位和0相与,其他位和1相与即可,所以得到x & ~(1<<(n-1))。

所以该宏为#define CLR_BIT_N(x,n) ((x) & ~(1<<((n)-1)))

2.7.3 截取变量的部分连续位

这个宏比较复杂,我们单独拿出来分析它。相信有了上面几节的学习,理解起来也不会难。该宏实现的是截取指定的连续位(n~m)作为一个新的值。例如变量0x88,也就是0b10001000,若截取第2~4位(bit0为第一位),则值为0b100 = 4。

define GETBITS(x, n, m) ((x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1))

我们看到上面这么一个复杂的宏怎么分析呢?提取对应的括号,将对应的括号分离出来,从最里边开始分析,然后将最里边视为一个整体,一层一层地向外边扩展分析。

分析:((x & ~(~(0U)<<(m-n+1))<<(n-1)) >> (n-1)) 提取最里边的括号对便是~(0U)<<(m-n+1),然后一层一层地往外面分析,如下所示。


d9842bf5fb0559d2945353cf4f3bede0f5048e1d

到目前,已经构造出来了bitn~bitm连续为1,其余位都为0的数。由前面的几节可知,将这个数与操作数x相与即可从操作数x截取到bitn~bitm位为原数不变,其余位全为0的数。假设该数为Y。
Y = (x & ~(~(0U)<<(m-n+1))<<(n-1))
AI 代码解读

然后只要再将Y右移位(n-1),即可得到以bitn~bitm构成的新数。

课后题
1.嵌入式系统中常常要求用户对变量或者寄存器进行位操作,下面的函数分别用于设置和清除变量a的第5位,请使用下面宏定义bit5,按要求对变量a进行相应的处理,在函数set_bit5中,用位或赋值操作(|=)设置变量a的第5位。在函数clear_bit5中,用位与赋值操作(&=)清除变量a的第5位。(软考题)

define BIT5 (0X01<<5)

static int a;

void set_bit(void)
{

______;
AI 代码解读

}
void clear_bit5(void)
{

______;
AI 代码解读

}
2.请描述如下位操作的作用。

a |= (1 << 3); 

a |= (0b11111 << 3); 或a |= (~((~0) << 5) << 3);

a &= ~(1 << 15);

a &= ~(0b111111111 << 15); 或a &= ~(~((~0) << 9) << 15);

a &= (0b111111 << 3); 或a &= (~((~0) << 6) << 3);   

3.请解释如下两个宏的含义。

#define SET_NTH_BIT(x, n) (x | ((1U)<<(n-1)))

#define CLEAR_NTH_BIT(x, n) (x & ~((1U)<<(n-1)))

4.截取变量的部分连续位,例如变量0x88, 也就是10001000,若截取第2~4位,则值为010 = 2,最右边从第0位算起,假设m=4,n=2。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
打赏
0
0
0
0
1811
分享
相关文章
Intel Linux 内核测试套件-LKVS介绍 | 龙蜥大讲堂104期
《Intel Linux内核测试套件-LKVS介绍》(龙蜥大讲堂104期)主要介绍了LKVS的定义、使用方法、测试范围、典型案例及其优势。LKVS是轻量级、低耦合且高代码覆盖率的测试工具,涵盖20多个硬件和内核属性,已开源并集成到多个社区CICD系统中。课程详细讲解了如何使用LKVS进行CPU、电源管理和安全特性(如TDX、CET)的测试,并展示了其在实际应用中的价值。
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
69 15
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
168 14
【C语言】数据类型全解析:编程效率提升的秘诀
在C语言中,合理选择和使用数据类型是编程的关键。通过深入理解基本数据类型和派生数据类型,掌握类型限定符和扩展技巧,可以编写出高效、稳定、可维护的代码。无论是在普通应用还是嵌入式系统中,数据类型的合理使用都能显著提升程序的性能和可靠性。
65 8
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
680 6
Linux操作系统的内核优化与性能调优####
本文深入探讨了Linux操作系统内核的优化策略与性能调优方法,旨在为系统管理员和高级用户提供一套实用的指南。通过分析内核参数调整、文件系统选择、内存管理及网络配置等关键方面,本文揭示了如何有效提升Linux系统的稳定性和运行效率。不同于常规摘要仅概述内容的做法,本摘要直接指出文章的核心价值——提供具体可行的优化措施,助力读者实现系统性能的飞跃。 ####
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
67 5
|
1月前
|
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
52 5

物联网

+关注

相关产品

  • 物联网平台