C语言数据结构笔记3:Union联合体+结构体取8位Bool量

本文衔接上文要求,新增8位bool量的获取方式。

目录

问题提出:

Union联合体+struct结构体(方式1):

Union联合体+struct结构体(方式2):

BYTE方式读取:


问题提出:

在STM32单片机的编程中,无法定义Bool或者bit类型

但有时候,比如modbus通信时,需要把bool量八个八个地组合读取,少于8个的部分填充0

Union联合体+struct结构体(方式1):

这里是考虑到超过8位的使用场景,因此定义了超过3字节的定义方式

这种方式适合那种喜欢一个一个列出所有寄存器位名称的情况。

cpp 复制代码
#define BITS_PER_BYTE 8
#define BYTES_FOR_BITS 3  //
 
// 定义3字节的位字段结构
typedef union {
    uint8_t bytes[BYTES_FOR_BITS];  // 整个字节数组访问
    struct {
        // 每个字节单独定义位字段
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } byte0;
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } byte1;
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } byte2;
    } bits;
} LargeBitField;
cpp 复制代码
#include <stdio.h>

typedef unsigned char uint8_t;
typedef unsigned short int    uint16_t;
typedef signed short int      int16_t;

#pragma pack(push, 1) //:将结构体的对齐方式设置为 1 字节,并将当前对齐设置保存到堆栈中。

//0x03e8 - 0x03ee
typedef struct  ABC_regs1
{
    uint16_t  A1;
    uint16_t  B1;
    int16_t   C1;
    int16_t   D1;
    uint16_t  E1;
    int16_t   F1;
    int16_t   G1;
}ABC_regs_1;

//0x177B - 0x1781
typedef struct  ABC_regs2
{
    uint16_t  A2;
    uint16_t  B2;
    int16_t   C2;
    int16_t   D2;
    uint16_t  E2;
    int16_t   F2;
    int16_t   G2;
}ABC_regs_2;

#define BITS_PER_BYTE 8
#define BYTES_FOR_BITS 3  //
 
// 定义15字节的位字段结构
typedef union {
    uint8_t bytes[BYTES_FOR_BITS];  // 整个字节数组访问
    struct {
        // 每个字节单独定义位字段
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } byte0;
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } byte1;
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } byte2;
    } bits;
} LargeBitField;


typedef struct  Letter_regs
{
    ABC_regs_1 ABC1;  //0x03e8 - 0x03f1 //7成员 14字节 //偏移量 0x00- 0x0c
    ABC_regs_2 ABC2;  //0x177B - 0x1781 //7成员 14字节 
    //BOOL_1     Bool1; //
    LargeBitField Bytes;
}letter_regs;



int main(void)
{
    letter_regs reg;


    // 设置位
    reg.Bytes.bits.byte0.b0 = 1;  // 设置byte0的第0位为1
    reg.Bytes.bits.byte1.b7 = 1;  // 设置byte1的第7位为1
 
    // 读取位
    uint8_t bit0 = reg.Bytes.bits.byte0.b0;
    uint8_t bit7 = reg.Bytes.bits.byte1.b7;
 
    printf("Bit 0 of byte0: %d\n", bit0);
    printf("Bit 7 of byte1: %d\n", bit7);
 
    // 通过字节数组访问
    reg.Bytes.bytes[0] = 0x0F;  // 设置byte0为0x0F
    printf("Byte 0: 0x%02X\n", reg.Bytes.bytes[0]);


}

Union联合体+struct结构体(方式2):

这种方式不一个一个列出寄存器名称,直接通过地址偏移操作:

cpp 复制代码
#include <stdio.h>

typedef unsigned char uint8_t;
typedef unsigned short int    uint16_t;
typedef signed short int      int16_t;

#pragma pack(push, 1) //:将结构体的对齐方式设置为 1 字节,并将当前对齐设置保存到堆栈中。

//0x03e8 - 0x03ee
typedef struct  ABC_regs1
{
    uint16_t  A1;
    uint16_t  B1;
    int16_t   C1;
    int16_t   D1;
    uint16_t  E1;
    int16_t   F1;
    int16_t   G1;
}ABC_regs_1;

//0x177B - 0x1781
typedef struct  ABC_regs2
{
    uint16_t  A2;
    uint16_t  B2;
    int16_t   C2;
    int16_t   D2;
    uint16_t  E2;
    int16_t   F2;
    int16_t   G2;
}ABC_regs_2;

// 定义字节的位字段结构
typedef union {
    uint8_t byte;  // 整个字节数组访问
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } bits;
}BitField;


typedef struct  Letter_regs
{
    ABC_regs_1 ABC1;  //0x03e8 - 0x03f1 //7成员 14字节 //偏移量 0x00- 0x0c
    ABC_regs_2 ABC2;  //0x177B - 0x1781 //7成员 14字节 
    BitField Bytes[10];
}letter_regs;



int main(void)
{
    letter_regs reg;
    // 通过直接赋值给联合体的字节
    reg.Bytes[0].byte = 0xA5;  // 0xA5 in hex is 10100101 in binary
 
    // 通过位域赋值
    reg.Bytes[1].bits.b0 = 1;  // Set bit 0 to 1
    reg.Bytes[1].bits.b7 = 1;  // Set bit 7 to 1
 
    // 读取并打印结果
    printf("Byte 0: 0x%02X\n", reg.Bytes[0].byte);  // 输出 0xA5
    printf("Byte 1: 0x%02X\n", reg.Bytes[1].byte);  // 输出 0x81 (因为 b7 和 b0 被设置为1)
 
}

BYTE方式读取:

cpp 复制代码
#include <stdio.h>

typedef unsigned char uint8_t;
typedef unsigned short int    uint16_t;
typedef signed short int      int16_t;
#pragma pack(push, 1) //:将结构体的对齐方式设置为 1 字节,并将当前对齐设置保存到堆栈中。

//0x03e8 - 0x03ee
typedef struct  ABC_regs1
{
    uint16_t  A1;
    uint16_t  B1;
    int16_t   C1;
    int16_t   D1;
    uint16_t  E1;
    int16_t   F1;
    int16_t   G1;
}ABC_regs_1;

//0x177B - 0x1781
typedef struct  ABC_regs2
{
    uint16_t  A2;
    uint16_t  B2;
    int16_t   C2;
    int16_t   D2;
    uint16_t  E2;
    int16_t   F2;
    int16_t   G2;
}ABC_regs_2;

// 定义字节的位字段结构
typedef union {
    uint8_t byte;  // 整个字节数组访问
        struct {
            uint8_t b0 : 1;
            uint8_t b1 : 1;
            uint8_t b2 : 1;
            uint8_t b3 : 1;
            uint8_t b4 : 1;
            uint8_t b5 : 1;
            uint8_t b6 : 1;
            uint8_t b7 : 1;
        } bits;
}BitField;

typedef struct  Letter_regs
{
    ABC_regs_1 ABC1;  //0x03e8 - 0x03f1 //7成员 14字节
    ABC_regs_2 ABC2;  //0x177B - 0x1781 //7成员 14字节 
    BitField Bytes[10]; //0x0400 - 0x0450 //80 成员 
}letter_regs;

int main(void)
{
    letter_regs reg;
    // 通过直接赋值给联合体的字节
    reg.Bytes[0].byte = 0xAA;  // 0xA5 in hex is 10100101 in binary
     reg.Bytes[8].byte = 0x6A;  // 0xA5 in hex is 10100101 in binary
    unsigned char* ptr = (unsigned char*)&reg.Bytes;

    //print_struct_values(&reg);

     //联合体读8个,实际物理地址才偏移1,相对于基地址地偏移量,都一个BYTE才偏移1
     for (int j = 0; j < 10; j++) //读10个BYTE 整个联合体
    {
        unsigned char offset = j; // 计算偏移量
        uint8_t value = *(const uint8_t*)(ptr + offset);
         printf("Byte %d: 0x%02X\n",j,value);
    }
}
相关推荐
Rabitebla10 小时前
【Linux 底层原理】进程(十):进程等待详解---从僵尸进程到 wait、waitpid 与 status
linux·c++·笔记·学习·visual studio
小lu飞11 小时前
2026小红书小工具怎么制作:纯前端 ZIP 打包、沙箱限制与笔记挂载流程
前端·笔记·ai·ai编程
无心水15 小时前
24、系统架构师论文写作专题 核心考点与学习笔记
笔记·学习·系统架构·架构师·安全架构·软考架构师·软考系统架构设计师
蒸蒸yyyyzwd15 小时前
邓明 Agent 系统面试-意图识别学习笔记
笔记·学习
Zhao-Jichao18 小时前
AI Prompting for Everyone 课程笔记 - P21 总结 Conclusion
人工智能·笔记
欢欢李18 小时前
【LTE L3 笔记 05】LTE同步信号
笔记·无线通信·物理层·lte·空口协议
La Pulga20 小时前
【FreeRTOS源码学习笔记】空闲任务与阻塞延时
笔记·mcu·学习·嵌入式·freertos·实时操作系统
蒸蒸yyyyzwd20 小时前
秋招学习笔记 day106
笔记·学习
小李不想当小白21 小时前
WDG看门狗(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
欢欢李1 天前
【LTE L3 笔记 04】LTE帧结构
笔记·无线通信·物理层·lte·空口协议