结构体对齐原则在自定义协议解析时的妙用之法
时间:2022-07-22
本文章向大家介绍结构体对齐原则在自定义协议解析时的妙用之法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
关于结构体对齐的设置,以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:%dn",sizeof(struct mystu));
printf("mystu0:%dn",sizeof(struct mystu0));
printf("mystu1:%dn",sizeof(struct mystu1));
printf("mystu2:%dn",sizeof(struct mystu2));
return 0 ;
}
运行结果:
根据这样的原理,在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%xn", Car_Procol->frame_top);
printf("版本:0x%xn", Car_Procol->version);
printf("方向:0x%xn", Car_Procol->car_direction);
printf("速度:0x%xn", Car_Procol->car_speed);
printf("炮台:0x%xn", Car_Procol->car_fort_status);
printf("夹具:0x%xn", Car_Procol->car_Fix_status);
printf("帧尾:0x%xn", Car_Procol->frame_tail);
rx_count = 0 ;
}
}
}
从这里可以看到,串口接收的数据是一个字节一个字节进行接收,所以接收的每个数据类型一致,我们就可以直接定义一个结构体,按照协议定义的顺序,将数据缓冲区中的数据依次读取出来。
在小熊派上的运行结果:
我在写上位机涉及到与MCU进行协议通信的时候,经常都是这么干的,这个方法不得不说真的超方便。
案例下载
公众号后台回复:protocol 即可获取本节案例的下载链接。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 史上最贴心React渲染器开发辅导
- 010.Nginx正反代理
- ClickHouse源码笔记2:聚合流程的实现
- 5G边缘计算赋能安防互联网直播行业,青犀视频强力打造云、边、端一体化协同音视频解决方案
- 视频云平台流媒体服务EasyNVR能获取直播视频的RTSP流地址吗?
- 如何编写不存在即插入的 SQL
- SQL 打印一个月的日历
- Kubernetes节点的驱逐与预留
- 使用reveal.js制作精美的网页版PPT
- Ceph快照爱你不容易系列 03:快照数据一致性浅析
- 没想到竟是因为它!让我的服务器变成了别人的挖矿工具
- 从零到一,Serverless 平台在滴滴内部落地
- React 使用 Proxy 代理(create-react-app)
- .Net Core + EF + mysql 从数据库生成实体
- Git 常用命令