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

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


......

相关推荐
卷卷的小趴菜学编程20 分钟前
c++之多态
c语言·开发语言·c++·面试·visual studio code
大白的编程日记.2 小时前
【C++笔记】C+11深度剖析(三)
c语言·开发语言·c++
和光同尘@3 小时前
56. 合并区间 (LeetCode 热题 100)
c语言·开发语言·数据结构·c++·算法·leetcode·职场和发展
YH_DevJourney3 小时前
Linux-C/C++《C/9、信号:基础》(基本概念、信号分类、信号传递等)
linux·c语言·c++
让我们一起加油好吗4 小时前
【数学】数论干货(疑似密码学基础)
c语言·visualstudio·密码学
许科大7 小时前
【笔记ing】C语言补充、组成原理数据表示与汇编实战、操作系统文件实战(高级阶段)
c语言
时时三省8 小时前
【时时三省】(C语言基础)求多项式1-1/2+1/3-1/4+...+1/99-1/100的值 用C语言表示
c语言
我不是程序猿儿14 小时前
【C】识别一份嵌入式工程文件
c语言·开发语言
子豪-中国机器人18 小时前
2月17日c语言框架
c语言·开发语言
张胤尘19 小时前
C/C++ | 每日一练 (2)
c语言·c++·面试