由字节对齐引发的一场“血案“

由字节对齐引发的一场“血案“最近在搞个网络通信协议 采用 socket udp 传输 运行时 居然报段错误了 经过 debug 发现居然是因为字节对齐问题导致的 这个问题在实现通信协议 是经常会遇到的问题 为了方便读者理解 我把内容做了简化 分享给大家

大家好,欢迎来到IT知识分享网。

最近在搞个网络通信协议,

采用socket udp传输,

运行时,居然报段错误了,

经过debug,发现居然是因为字节对齐问题导致的。

这个问题在实现通信协议,是经常会遇到的问题,

为了方便读者理解,

我把内容做了简化,分享给大家。

1、协议说明

通信协议信令格式如下:

typedef struct protocol_msg_s{ UINT8 msgType; UINT8 data1; UINT8 data2; UINT16 len; char data[100]; }PRO_MSG; 
由字节对齐引发的一场“血案“

根据协议格式,我造了一个数据frm,代表我收到的某个信令,

 UCHAR frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; 

根据协议,

信令的字段与原始帧对应关系如下

由字节对齐引发的一场“血案“

于是我实现了一个简单的解析代码【该代码有问题】

int main(int argc, char argv) { int ret; int frm_len = 0; UINT8 frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; PRO_MSG *pmsg = (PRO_MSG *)frm; printf("devType:%02x data1:%02x data2:%02x len:%04x \n", pmsg->msgType, pmsg->data1, pmsg->data2, pmsg->len); } 

编译运行后,其中len的值居然是0107,而不是0007

由字节对齐引发的一场“血案“

这其实就是因为编译器采用了字节对齐导致的,

在给pmsg->len赋值时,因为需要2个字节,

这两个字节是frm[3]、frm[4]这正好分布在两个字里,

编译器忽略了frm[3],最终将frm[4]、frm[5]合在一起赋值给了pmsg->len

由字节对齐引发的一场“血案“

为什么有字节对齐?

简单的说内存对齐能够提高 cpu 读取数据的速度,减少 cpu 访问数据的出错性(有些 cpu 必须内存对齐,否则指针访问会出错)。

原因找到了,下面就是解决了。

2、解决办法

1. 方法1 #pragma pack()

该预处理指令用来改变对齐参数。在缺省情况下,C编译器为每一个变量或数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对齐参数:

使用伪指令#pragma pack (n),C编译器将按照n字节对齐。 使用伪指令#pragma pack (),取消自定义字节对齐方式。 

完整代码

#include <stdio.h> #include <string.h> typedef unsigned char UINT8; typedef unsigned short UINT16; #define MAX_FRM_DATA_LEN 100 #pragma pack(1) typedef struct protocol_msg_s{ UINT8 msgType; UINT8 data1; UINT8 data2; UINT16 len; char data[MAX_FRM_DATA_LEN]; }PRO_MSG; #pragma int main(int argc, char argv) { int ret; int frm_len = 0; UINT8 frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; PRO_MSG *pmsg = (PRO_MSG *)frm; printf("devType:%02x data1:%02x data2:%02x len:%04x \n", pmsg->msgType, pmsg->data1, pmsg->data2, pmsg->len); } 
由字节对齐引发的一场“血案“

2. 方法2

老老实实将收到的数据帧逐字节解析,

并填充到struct protocol_msg_s

#include <stdio.h> #include <string.h> typedef unsigned char UINT8; typedef unsigned short UINT16; #define MAX_FRM_DATA_LEN 100 typedef struct protocol_msg_s{ UINT8 msgType; UINT8 data1; UINT8 data2; UINT16 len; char data[MAX_FRM_DATA_LEN]; }PRO_MSG; int frm_parse(PRO_MSG *pmsg,UINT8 buf[],int len) { int pos=0; pmsg->msgType = buf[pos]; pos++; pmsg->data1 = buf[pos]; pos++; pmsg->data2 = buf[pos]; pos++; pmsg->len = buf[pos]<<8 | buf[pos+1]<<0; pos+=2; if(pmsg->len>MAX_FRM_DATA_LEN) { printf("frm len is longer than 100\n"); return -1; } memcpy(pmsg->data,&buf[pos],pmsg->len); return 0; } int maini(int argc, char argv) { int ret; int frm_len = 0; UINT8 frm[]={0x12,0x34,0x56,0x00,0x07,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; PRO_MSG msg; PRO_MSG *pmsg = &msg; frm_len = sizeof(frm); ret = frm_parse(pmsg,frm,frm_len); if(ret<0) { printf("frm_parse fail\n"); return -1; } printf("devType:%02x data1:%02x data2:%02x len:%04x \n", pmsg->msgType, pmsg->data1, pmsg->data2, pmsg->len); return 0; } 
由字节对齐引发的一场“血案“

end

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/95530.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信