C 位域的作用

1-1 位域


C 语言中位域的作用,这是一个典型的位域应用案例

cpp 复制代码
typedef union {
    struct {
        volatile    U8  b_dot_BAT1     :1;    //电池框
        volatile    U8  b_dot_BAT2     :1;    //从左到右 第一格
        ......
   }_bit;
}SEG_DSP_FLAG7;

位域的基本概念:结构体可以指定成员占用的位数,这就是位域。使用冒号加数字,比如:1,表示这个成员只占1个二进制位。这样做的好处是可以节省内存,尤其是在处理硬件寄存器或者需要紧凑存储数据的时候。代码中 :1 是 **C语言结构体位域(Bit Field)**的语法,用于指定结构体成员占用的内存位数。


1-2 作用


位域允许你精确控制结构体成员占用的内存位数(而非默认的字节单位),常用于:


节省内存空间:将多个布尔值或小范围整数值压缩存储在一个字节(或整型变量)中。

硬件映射:直接操作寄存器或硬件设备的特定位(如状态标志位)。

代码可读性:用名称直接访问特定位,代替手动位掩码和位移操作。


1-3 分析


cpp 复制代码
typedef union {
    struct {
        volatile U8 b_dot_BAT1    :1; // 电池框
        volatile U8 b_dot_BAT2    :1; // 从左到右 第一格
        volatile U8 b_dot_BAT3    :1; // 从左到右 第二格
        // ... 其他成员类似
    } _bit;
} SEG_DSP_FLAG7;

位域语法 :每个成员后的 :1 表示它占用 1个二进制位 (即只能存储 0 1)。

结构体总大小 :所有成员位数之和不超过底层类型(此处是 U8,即1字节 = 8位)。本例中共有8个1位成员,正好占满1字节。

联合体 (Union)SEG_DSP_FLAG7 是一个联合体,目的是让 _bit 结构体和可能的其他成员(如一个完整的 U8 字节)共享同一内存空间,方便通过位域或字节整体操作。


1-4 案例


cpp 复制代码
typedef union {
    struct {
        volatile U8 b_dot_BAT1    :1; // 电池框
        volatile U8 b_dot_BAT2    :1; // 从左到右 第一格
        volatile U8 b_dot_BAT3    :1; // 从左到右 第二格
        // ... 其他成员类似
    } _bit;
} SEG_DSP_FLAG7;

位域语法 :每个成员后的 :1 表示它占用 1个二进制位 (即只能存储 0 1)。

结构体总大小 :所有成员位数之和不超过底层类型(此处是 U8,即1字节 = 8位)。本例中共有8个1位成员,正好占满1字节。

联合体 (Union)SEG_DSP_FLAG7 是一个联合体,目的是让 _bit 结构体和可能的其他成员(如一个完整的 U8 字节)共享同一内存空间,方便通过位域或字节整体操作。


1-5 案例


假设我们要控制一个LED状态寄存器,其中:

第0位:LED开关(1开/0关)

第1位:颜色模式(1红色/0绿色)

第2-4位:亮度等级(0-7)


位域实现部分代码

cpp 复制代码
typedef union {
    struct {
        volatile uint8_t led_on    :1;  // 位0:开关
        volatile uint8_t color     :1;  // 位1:颜色模式
        volatile uint8_t brightness:3;  // 位2-4:亮度(3位可表示0-7)
        volatile uint8_t reserved  :3;  // 位5-7:保留位
    } bits;
    volatile uint8_t byte; // 整个字节的视图
} LED_Register;

// 使用示例
LED_register reg;
reg.bits.led_on = 1;       // 打开LED
reg.bits.color = 1;        // 设为红色
reg.bits.brightness = 5;   // 亮度级别5

1-6 注意事项


位域的顺序

1:位的分配顺序(从左到右还是从右到左)依赖编译器和平台 。例如,某些编译器可能将 b_dot_BAT1 放在最低位(LSB),而另一些放在高位(MSB)。

2:可通过调试或文档验证实际布局。

3:位域的具体实现可能因编译器而异,在跨平台代码中需谨慎使用。

4:此处 volatile 表示变量可能被外部硬件或中断修改,禁止编译器优化访问(确保每次读写直接操作内存)


手动操作:

如果不使用位域,等效的手动位操作如下

在表达式 led_register |= (1 << 0); 中,(1 << 0) 实际上表示数字1左移0位。根据位移操作的定义,任何数左移0位都是其本身。也就是说,1 << 0 的结果还是1。这个操作不会改变数值1的值。

明确性:即使左移0位不改变值,这种写法可以增加代码的可读性和明确性,表明你有意将第0位设置为1。这对于理解代码的人来说是一个清晰的信号,即该位是有意被设定的。

**一致性:**如果在代码中存在多个类似的操作(例如设置不同的位),使用统一的位移操作格式可以使代码更加一致和易于维护。比如,若你需要设置第1位,则可以使用 (1 << 1),对于第2位则使用 (1 << 2) 等等。这样做的好处是显而易见的,特别是当你需要快速定位到某一位进行操作时。

cpp 复制代码
uint8_t led_register = 0;

// 设置LED开关为1
led_register |= (1 << 0); 

// 设置颜色模式为红色
led_register |= (1 << 1); 

// 设置亮度为5(需清除旧值后设置)
led_register &= ~(0x7 << 2);  // 清除位2-4
led_register |= (5 << 2);     // 设置亮度5

相比之下,位域代码更简洁直观


......

相关推荐
Tingjct11 小时前
【初阶数据结构-二叉树】
c语言·开发语言·数据结构·算法
飞机和胖和黄12 小时前
考研之王道C语言第三周
c语言·数据结构·考研
醉颜凉12 小时前
【LeetCode】打家劫舍III
c语言·算法·leetcode·树 深度优先搜索·动态规划 二叉树
一匹电信狗12 小时前
【LeetCode_21】合并两个有序链表
c语言·开发语言·数据结构·c++·算法·leetcode·stl
卢锡荣15 小时前
Type-c OTG数据与充电如何进行交互使用应用讲解
c语言·开发语言·计算机外设·电脑·音视频
v_for_van16 小时前
力扣刷题记录2(无算法背景,纯C语言)
c语言·算法·leetcode
二年级程序员16 小时前
动态内存管理
c语言
我能坚持多久16 小时前
D20—C语言文件操作详解:从基础到高级应用
c语言·开发语言
(❁´◡`❁)Jimmy(❁´◡`❁)16 小时前
CF2188 C. Restricted Sorting
c语言·开发语言·算法
想放学的刺客17 小时前
单片机嵌入式试题(第27期)设计可移植、可配置的外设驱动框架的关键要点
c语言·stm32·单片机·嵌入式硬件·物联网