结构体对齐原则在自定义协议解析时的妙用之法

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 结构体对齐原则在自定义协议解析时的妙用之法

关于结构体对齐的设置,以GCC 32bit编译为例,我们可以来看看下面这个例子:

#include <stdio.h>
//默认情况下,结构体一般在内存中的自动对齐格式是4个字节 
//结构体设置手动对齐 
//如果这里是4,那么下面的打印就是8     
//如果这里是2,那么下面的打印就是6    
//如果这里是1,那么下面的打印就是5 
struct mystu
{
     char a ; 
     int  b ;
};
#pragma pack(4)
struct mystu0
{
     char a ; 
     int  b ;
};
#pragma pack()
#pragma pack(2)
struct mystu1
{
     char a ; 
     int  b ;
};
#pragma pack()
#pragma pack(1)
struct mystu2
{
     char a ; 
     int  b ;
};
#pragma pack() 
int main(void)
{
     printf("mystu:%d\n",sizeof(struct mystu));
     printf("mystu0:%d\n",sizeof(struct mystu0));
     printf("mystu1:%d\n",sizeof(struct mystu1));
     printf("mystu2:%d\n",sizeof(struct mystu2));
     return 0 ;
}

运行结果:

640.png

根据这样的原理,在MCU协议数据解析的时候就很有作用了,比如下面这个例子,目前在小车上用:

//结构体,用于存储解析的数据
typedef struct
{
 //帧头(固定解析为FF)
    uint8_t frame_top ;   
 //版本 A1
    uint8_t version ;
 //方向 01(前进) 02(后退) 03(左转) 04(右转)
    uint8_t car_direction ;
 //速度 01(低速档) 02(中速档) 03(高速档)
    uint8_t car_speed ;
 //炮台 00(回到中间) 01(炮台左转) 02(炮台右转)
    uint8_t car_fort_status ;
 //夹具 00(夹具夹紧) 01(夹具松开)
 uint8_t car_Fix_status ;
 //帧尾(固定解析为BB)
    uint8_t frame_tail ;
} Protocol;
//以下是串口回调的处理
/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
    /* USER CODE BEGIN USART1_IRQn 0 */
    /*自定义协议*/
    /*
     帧头 版本 方向 速度 炮台 夹具 帧尾
     ff   A1
    */
    uint8_t Res;
    if((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET))
    {
        HAL_UART_Receive(&huart1, &Res, 1, 1000);
        if(0xBB != Res)
        {
            rbBuf[rx_count++] = Res ;
        }
        else
        {
            rbBuf[rx_count] = 0xBB ;
            //接收到0xBB了,这时候认为已经接收到完整的一帧数据,将接收标志置1
            Recv_Flag = 1 ;
        }
        /* USER CODE END USART1_IRQn 0 */
        HAL_UART_IRQHandler(&huart1);
        /* USER CODE BEGIN USART1_IRQn 1 */
        /* USER CODE END USART1_IRQn 1 */
    }
    /* USER CODE BEGIN 1 */
    /* USER CODE END 1 */
}
//在主函数中,进行数据解析
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    while (1)
    {
        if(1 == Recv_Flag)
        {
            Recv_Flag = 0 ;
            //将接收缓冲区的数组强制转换为一个结构体指针
            //通过结构体指针可访问到每一个协议规格的数据
            Protocol *Car_Procol = (Protocol *)rbBuf;
            printf("帧头:0x%x\n", Car_Procol->frame_top);
            printf("版本:0x%x\n", Car_Procol->version);
            printf("方向:0x%x\n", Car_Procol->car_direction);
            printf("速度:0x%x\n", Car_Procol->car_speed);
            printf("炮台:0x%x\n", Car_Procol->car_fort_status);
            printf("夹具:0x%x\n", Car_Procol->car_Fix_status);
            printf("帧尾:0x%x\n", Car_Procol->frame_tail);
            rx_count = 0 ;
        }
    }
}

从这里可以看到,串口接收的数据是一个字节一个字节进行接收,所以接收的每个数据类型一致,我们就可以直接定义一个结构体,按照协议定义的顺序,将数据缓冲区中的数据依次读取出来。


在小熊派上的运行结果:

640.png

我在写上位机涉及到与MCU进行协议通信的时候,经常都是这么干的,这个方法不得不说真的超方便。

案例下载

公众号后台回复:protocol 即可获取本节案例的下载链接。

往期精

【为宏正名】本应写入教科书的“世界设定”


【为宏正名】99%人都不知道的"##"里用法


学习嵌入式可以带娃,不信你们看


ESP8266实战贴:使用HTTP POST请求上传数据到公有云OneNet

目录
相关文章
|
C语言
C语言结构体使用及解析
C语言结构体使用及解析
222 0
|
7月前
|
存储 编译器 Linux
【C语言】自定义类型:结构体深入解析(二)结构体内存对齐&&宏offsetof计算偏移量&&结构体传参
【C语言】自定义类型:结构体深入解析(二)结构体内存对齐&&宏offsetof计算偏移量&&结构体传参
|
3月前
|
存储 JSON API
深入解析RESTful API设计原则与实践
【9月更文挑战第21天】在数字化时代,后端开发不仅仅是编写代码那么简单。它关乎于如何高效地连接不同的系统和服务。RESTful API作为一套广泛采用的设计准则,提供了一种优雅的解决方案来简化网络服务的开发。本文将带你深入了解RESTful API的核心设计原则,并通过实际代码示例展示如何将这些原则应用于日常的后端开发工作中。
|
2天前
|
设计模式 Java 程序员
【23种设计模式·全精解析 | 概述篇】设计模式概述、UML图、软件设计原则
本系列文章聚焦于面向对象软件设计中的设计模式,旨在帮助开发人员掌握23种经典设计模式及其应用。内容分为三大部分:第一部分介绍设计模式的概念、UML图和软件设计原则;第二部分详细讲解创建型、结构型和行为型模式,并配以代码示例;第三部分通过自定义Spring的IOC功能综合案例,展示如何将常用设计模式应用于实际项目中。通过学习这些内容,读者可以提升编程能力,提高代码的可维护性和复用性。
【23种设计模式·全精解析 | 概述篇】设计模式概述、UML图、软件设计原则
|
20天前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
104 14
|
2月前
|
架构师 关系型数据库 MySQL
MySQL最左前缀优化原则:深入解析与实战应用
【10月更文挑战第12天】在数据库架构设计与优化中,索引的使用是提升查询性能的关键手段之一。其中,MySQL的最左前缀优化原则(Leftmost Prefix Principle)是复合索引(Composite Index)应用中的核心策略。作为资深架构师,深入理解并掌握这一原则,对于平衡数据库性能与维护成本至关重要。本文将详细解读最左前缀优化原则的功能特点、业务场景、优缺点、底层原理,并通过Java示例展示其实现方式。
126 1
|
3月前
|
存储 Shell Go
Go语言结构体和元组全面解析
Go语言结构体和元组全面解析
|
6月前
结构体\判断日期是否合法(代码分步解析)
结构体\判断日期是否合法(代码分步解析)
43 1
|
7月前
|
存储 程序员 数据处理
C语言中的结构体:深入解析与应用
C语言中的结构体:深入解析与应用
|
7月前
|
编译器 C语言
【C语言】自定义类型:结构体深入解析(一)
【C语言】自定义类型:结构体深入解析(一)

热门文章

最新文章

推荐镜像

更多