• 正文
    • 1、協(xié)議說明
    • 2、解決辦法
  • 推薦器件
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

通信協(xié)議報(bào)錯(cuò)?由字節(jié)對齊引發(fā)的一場“血案”

2024/07/23
1566
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

最近在搞個(gè)網(wǎng)絡(luò)通信協(xié)議,采用socket udp傳輸,運(yùn)行時(shí),居然報(bào)段錯(cuò)誤了,經(jīng)過debug,發(fā)現(xiàn)居然是因?yàn)樽止?jié)對齊問題導(dǎo)致的。

這個(gè)問題在實(shí)現(xiàn)通信協(xié)議,是經(jīng)常會遇到的問題,為了方便讀者理解,我把內(nèi)容做了簡化,分享給大家。

1、協(xié)議說明

通信協(xié)議信令格式如下:

typedef?struct?protocol_msg_s{
?UINT8?msgType;
?UINT8?data1;
?UINT8?data2;
?UINT16?len;
?char?data[100];
}PRO_MSG;

根據(jù)協(xié)議格式,我造了一個(gè)數(shù)據(jù)frm,代表我收到的某個(gè)信令,

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

根據(jù)協(xié)議,信令的字段與原始幀對應(yīng)關(guān)系如下

于是我實(shí)現(xiàn)了一個(gè)簡單的解析代碼【該代碼有問題】

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);
}

編譯運(yùn)行后,其中l(wèi)en的值居然是0107,而不是0007

這其實(shí)就是因?yàn)?a class="article-link" target="_blank" href="/baike/1572830.html">編譯器采用了字節(jié)對齊導(dǎo)致的,

在給pmsg->len賦值時(shí),因?yàn)樾枰?個(gè)字節(jié),

這兩個(gè)字節(jié)是frm[3]、frm[4]這正好分布在兩個(gè)字里,

編譯器忽略了frm[3],最終將frm[4]、frm[5]合在一起賦值給了pmsg->len

為什么有字節(jié)對齊?

簡單的說內(nèi)存對齊能夠提高 cpu 讀取數(shù)據(jù)的速度,減少 cpu 訪問數(shù)據(jù)的出錯(cuò)性(有些 cpu 必須內(nèi)存對齊,否則指針訪問會出錯(cuò))。

原因找打了,下面就是解決了。

2、解決辦法

1. 方法1 #pragma pack()

該預(yù)處理指令用來改變對齊參數(shù)。在缺省情況下,C編譯器為每一個(gè)變量或數(shù)據(jù)單元按其自然對界條件分配空間。一般地,可以通過下面的方法來改變?nèi)笔〉膶R參數(shù):

使用偽指令#pragma?pack?(n),C編譯器將按照n字節(jié)對齊。

使用偽指令#pragma?pack?(),取消自定義字節(jié)對齊方式。

完整代碼

#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

老老實(shí)實(shí)將收到的數(shù)據(jù)幀逐字節(jié)解析,

并填充到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?100n");
??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?failn");
??return?-1;
?}

?printf("devType:%02x?data1:%02x?data2:%02x?len:%04x?n",
???pmsg->msgType,
???pmsg->data1,
???pmsg->data2,
???pmsg->len);
?return?0;
}


推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險(xiǎn)等級 參考價(jià)格 更多信息
ECS-250-12-33-AGN-TR 1 ECS International Inc Parallel - Fundamental Quartz Crystal,
$0.52 查看
HCNW3120-000E 1 Agilent Technologies Inc IC Output Optocoupler, 1-Element, 5000V Isolation,
$4.36 查看
DS24B33+T&R 1 Maxim Integrated Products EEPROM, 4KX1, Serial, CMOS, PBCY3, ROHS COMPLIANT, TO-92, 3 PIN
$2.92 查看

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗(yàn)和培訓(xùn)經(jīng)驗(yàn)。曾任職ZTE,某研究所,華清遠(yuǎn)見教學(xué)總監(jiān)。擁有多篇網(wǎng)絡(luò)協(xié)議相關(guān)專利和軟件著作。精通計(jì)算機(jī)網(wǎng)絡(luò)、Linux系統(tǒng)編程、ARM、Linux驅(qū)動(dòng)、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實(shí)際項(xiàng)目出發(fā),保持原理+實(shí)踐風(fēng)格,適合Linux驅(qū)動(dòng)新手入門和技術(shù)進(jìn)階。