/* 前言:
* 我们在使用buf数字传输数据的时候,通常会用来传输各种数据类型。
* 一般的,我们会传输 char,short ,int ,float等,也包括各种 unsigned.
*
*
* 一般的思路我们在发送的时候,会把数据一个个拆解成一个个byte,然后按顺序放到buf。
* 在拿数据的时候,再一个一个的byte去拼接成具体数据,如下:
* //包装数据
buf[0]=Para.nv_list.sn>>24&0xff;
buf[1]=Para.nv_list.sn>>16&0xff;
buf[2]=Para.nv_list.sn>>8&0xff;
buf[3]=Para.nv_list.sn;
//拆解数据
RX_info_s.sn=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3]; //SN
*
*这样做思路非常的清晰,很直观,但是非常的累人,一个32的数据就得这样搞,如果有100个呢,你不得累死?
* 之前的文章也有提到过读写flash的方式,用的是结构体+联合体映射方式跳过这一步,那个是应用到一个
* nv参数列表的,适合大的buf包。想了解的可以去看看我之前的blog
*
* 疑问:
* 那如果我一个buf都只有几个数据呢,比如有4个数据 char,short ,int ,float,
* 如何快速的封包和拆包呢?下面我们一步步看看。
*
*
*
*/
这次呢,我们来优化一下上次的方法。基本思想还是flash那篇文章,利用结构体和联合体
核心代码:
//编写一个内存copy函数
#define MCOPY(S,T,L) do{int i=0;for(;i<L;i++)S[i]=T[i];}while(0)
//定义一个联合体来映射结构体
typedef union
{
typedef struct
{
char type; //协议类型
short para_short;
int para_int;
float para_float;
}PACK_XX_S; //XX代表包的名字,自定义
char buf[sizeof (PACK_XX_S)]; //自动算struct大小,通用性变强
PACK_XX_S nv_list;
}PACK_XX_U;
本次的修改,是把数据结构体放到了联合体里面,这样会显得代码更加的干净,而且结构体本身就只有联合体才可以访问。
模拟使用方法:(因为最近在学习QT,使用的QT环境)
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//一个发送数据包,一个接受数据包
PACK_XX_U send_XX_pack;
PACK_XX_U recv_XX_pack;
//一个发送缓存包,一个接受缓存包
//里面可能带头包头,检验等等
char send_buf[13]={0};
char recv_buf[13]={0};
send_XX_pack.nv_list.type =1;
send_XX_pack.nv_list.para_short =2;
send_XX_pack.nv_list.para_int =3;
send_XX_pack.nv_list.para_float =4.1234;
printf("send\n");
printf("type %d ",send_XX_pack.nv_list.type);
printf("type %d ",send_XX_pack.nv_list.para_short);
printf("type %d ",send_XX_pack.nv_list.para_int);
printf("type %f \n",send_XX_pack.nv_list.para_float);
//把数据拷贝到发送buf中,copy的位置根据自己协议定义
MCOPY(send_buf,send_XX_pack.buf,12);
//模拟收到数据
MCOPY(recv_buf,send_buf,12);
//把接收到的数据给数据包
MCOPY(recv_XX_pack.buf,recv_buf,12);
printf("recv\n");
printf("type %d ",recv_XX_pack.nv_list.type);
printf("type %d ",recv_XX_pack.nv_list.para_short);
printf("type %d ",recv_XX_pack.nv_list.para_int);
printf("type %f ",recv_XX_pack.nv_list.para_float);
fflush(stdout);
while(1);
return a.exec();
}
运行结果:
可以看到 recv_XX_pack这个数据包,没有进行任何类型的值copy,只进行了内存copy,直接拿到了所有值,在封包的过程,也只有值和值的传递,不需要拆解byte。
以后如果需要增加协议包,只需要复制一份联合体,然后重新定义结构体中的数据即可。
例如你要发送一个3轴数据包,如下,修改点非常少,直接可以使用,这么干货,yyds给一个吧
//定义一个联合体来映射结构体
typedef union
{
typedef struct
{
char type; //协议类型
float X;
float Y;
float Z;
}PACK_XX_S; //XX代表包的名字,自定义
char buf[sizeof (PACK_XX_S)]; //为什么是12?,因为结构体内存对齐问题
PACK_XX_S nv_list;
}PACK_ANGLE_U;
我们还可以继续优化联合体的内容,让它变得更加简洁。目前优化到最简洁的写法。如下
使用方法不变
typedef union
{
struct PACK_XX_S
{
char type; //protocol type
short para_short;
int para_int;
float para_float;
}nv_list; //XX is packet name
char buf[sizeof (struct PACK_XX_S)];
}PACK_XX_U;