结构体嵌入共联体在协议解析中的技术性操作过程

描述

 

1、正文部分  

1

话题引出

技术交流群一个小哥贴出了如下图片 :

  uart通信   uart通信

问到了共联体类型强制转化的问题,当时bug菌点开看到这几行代码便产生了莫名的亲切感,或许这些就是C语言的魅力所在吧。

其实这种操作在通信协议中拆包、解包是非常常见的,但是笔者也是在参加工作以后在部门的代码中get到,所以这里整理分享给各位。

2

操作解析

有认真阅读过笔者公众号文章的小伙伴,应该在其他文章中也看到过这种操作,不过比较分散,今天抽出来再好好聊聊!

1

buff直接转结构体

uart通信

上图是简单的协议包,包括帧头,长度和数据部分,在通信数据接收或者发送末端其都位于字节流中,比如UART通信,最后都是放到Sendbuff[N]或者RecBuff[N],然后发送出去。

如果你打包好了结构体,然后一个个填充byte到发送或者接受buff,着实有点麻烦,然而通过结构体指针强制类型转换为uint8_t *pSendBuff;然后在进行字节流发送,那就简洁很多了。

当然在此过程中你还要注意字节序、对齐等等,在往期的文章中bug菌都有讲到,模拟此过程参考下面代码。

参考示例:

 

#include 
#include 

#pragma pack(1)
typedef struct _tag_Pack
{
    int Head;
    int Len;
    char Data[2];
} sPack;

int main(int argc, char *argv[]) {
    sPack stSendPack;
    sPack *pstRevPack = NULL;
    unsigned char *SendBuff =NULL;
    unsigned char  RevBuff[20] ={0};
    int cnt = 0;

    //模拟封包 
    stSendPack.Head = 0xFF;
    stSendPack.Len = 0x08;
    stSendPack.Data[0] = 0x1;
    stSendPack.Data[1] = 0x2;

    //模拟发送包
    SendBuff = (unsigned char *)(&stSendPack);

    printf("SendData: ") ;
    for(cnt = 0 ;cnt < sizeof(sPack);cnt++)
    {
        printf("0x%02X  ",*(SendBuff + cnt)) ;
        RevBuff[cnt] = *(SendBuff + cnt);  //这里模拟接受到数据 
    } 

     printf("

");
    //模拟解包 
     pstRevPack = (sPack *)RevBuff;
     printf("pstRevPack.Head    = 0x%X
",pstRevPack->Head) ;
     printf("pstRevPack.Len     = 0x%X
",pstRevPack->Len) ;
     printf("pstRevPack.Data[0] = 0x%X
",pstRevPack->Data[0]) ;
     printf("pstRevPack.Data[1] = 0x%X
",pstRevPack->Data[1]) ;

    printf("
欢迎关注公众号:最后一个bug
");
    return 0;
}

 

运行结果:

uart通信

2

buff直接转结构共联体 

uart通信

上一节我们谈到了接受和发送的buff直接转结构体,然后进行解包处理,而交流群里面图片中是转共联体,可以说这样的数据结构结合是非常完美的。

buff转结构体类型,就必须buff字节流里的格式与结构体一致,才能正确的解析,而共联体是一种复合类型结构,可以存在多种形式的数据提取,这样就可以带来更多的灵活度,下面代码在操作一波。

参考示例:

 

#include 
#include 

#pragma pack(1)
typedef struct _tag_PackType1
{
    int Head;
    int Len;
    char Data[2];
} sPackType1;

typedef struct _tag_PackType2
{
    int Head;
    int Len;
    int Data[2];
} sPackType2;

typedef struct _tag_PackType3
{
    int Head;
    int Len;
    float Data[2];
} sPackType3;

//结构共联体
typedef union _tag_PackType
{
    sPackType1 stPackType1;
    sPackType2 stPackType2;
    sPackType3 stPackType3;
} uPackType;

//不同结构体类型的解析函数
void ParsePackType1(uPackType *punPackType)
{
    punPackType->stPackType1.Head = 0xF1;
    //you do something! 
}

void ParsePackType2(uPackType *punPackType)
{
    punPackType->stPackType2.Head = 0xF2;
    //you do something! 
}

void ParsePackType3(uPackType *punPackType)
{
    punPackType->stPackType3.Head = 0xF3;
    //you do something! 
}
/******************************************
 * Fuction: Buff转结构共联体 
 * Author :(公众号:最后一个bug) 
 *****************************************/ 
int main(int argc, char *argv[]) {

    uPackType *punPackType;
    unsigned char  RevBuff[20] ={0};

    //通信字节流接受到 RevBuff以后强转 
    punPackType = (uPackType*)RevBuff;

    //根据自身需要,不同的解析函数,统一传递共联体即可 
    ParsePackType1(punPackType);
    ParsePackType2(punPackType);
    ParsePackType3(punPackType); 

    printf("
欢迎关注公众号:最后一个bug
");
    return 0;
}

 

以上就是今天的全部内容,enjoy!





审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分