c語言結構體在嵌入式自定義通訊協議中的一些體會

2021-09-27 11:59:25 字數 1590 閱讀 3950

結構體可以把多種資料型別整合在一起,這樣在運算元據的時候只需要定義乙個結構體變數就可以了,而不必另外再定義很多的變數。

開發嵌入式軟體的時候,在兩個裝置的通訊,通常會自定義乙個內部的通訊協議,按照這個通訊通訊協議來收發資料,解析資料。

例如:

可以看到這個資料幀有9個字段,這樣的乙個資料幀如果能用乙個結構體來描述,那麼對於應用程式程式設計來說,會是非常的便利和清晰。但是用結構體來描述這乙個資料幀,有很多需要注意的問題。

一、乙個幀的資料在記憶體上需要保持連續,不能間斷。

在兩個裝置之間的通訊是嚴格按照約定好的協議來工作的,如果裝置a和裝置b通訊,裝置a包裝了乙個資料幀,但是在資料幀的某一處空了乙個字元,然後發給了裝置b,那麼裝置b按照這個協議來解析這個資料幀,在空了乙個字元的前面資料,應該都能解析成功,但是在這後面,應該就會解析錯誤了。

所以在利用結構體在描述乙個資料幀的時候,需要確保結構體內的每乙個欄位在記憶體上都是連續排放的。

二、在結構體如何保證每個字段記憶體的連續性

如果有以下結構體

struct command_frame

怎麼能保證記憶體位址連續性呢?

1、首先需要知道,結構體的位元組對齊

需要位元組對齊的根本原因在於cpu訪問資料的效率問題。例如,假設乙個處理器總是從儲存器中取出8個位元組,則位址必須為8的倍數。如果我們能保證將所有的double型別資料的位址對齊成8的倍數,那麼就可以用乙個儲存器操作來讀或者寫值了。否則,我們可能需要執行兩次儲存器訪問,因為物件可能被分放在兩個8位元組儲存塊中。因此在linux c中,結構體是自動開啟結構體對齊的。

一旦有了結構對齊,假如4位元組對齊,也許乙個char 型資料,會占用四個位元組的記憶體(其實還是占用乙個位元組的記憶體,只不過後面的三個位元組是空出來了),當然這個也要和結構體內的字段排放順序有關。這樣,乙個結構體的每乙個欄位在記憶體上就不是連續了,因此需要取消位元組對齊,才能用作資料幀來傳送。

取消位元組對齊的方法

#pragma pack(1)  //其實是按照乙個位元組對齊,即保證了每乙個位元組的連續性
2、其次需要注意結構體內的指標型別

如上面的結構體,有乙個成員 char *data,因為在通訊過程中,也許需要攜帶的資料長度是不定的,所以只能通過動態分配來精準分配記憶體。在c語言中,指標是必須需要初始化後才使用,因此我們在使用這個結構體當做資料幀的時候,需要通過mallco函式來精準的分配記憶體,但是通過malloc來分配的記憶體,是在堆上面,如果你的結構體變數是分配在棧上面的話,那麼記憶體的連續性就會中斷。就算把結構體變數也分配到堆上面,那又如何能把成員變數中的記憶體和結構體變數中的記憶體保持連續性呢?結論是不能的,因為乙個malloc函式分配記憶體的位址是不定的。

如果結構體內不用指標改用如下

struct command_frame

在取消位元組對齊後,上面的結構體可以保證位址的連續性。

但是這樣做,是需要在雙方裝置都指定資料的長度為255,即不管真實資料有多長1個位元組,還是10個位元組,資料字段都是占用255位元組。這樣雙方通訊,通過這個結構體可以通訊。

嵌入式LinuxQT操作自定義按鍵

嵌入式linux系統中,用qt做的應用層程式,需要檢測自定義的按鍵狀態。使用的qt的按鍵事件,驅動層使用的linux的input子系統。環境如下 硬體 imx6ull qt版本 5.5 在qt中使用按鍵事件檢測按鍵狀態基本上由三部分工作組成 1 驅動層 2 環境變數 3應用層 1 驅動層 首先開起l...

嵌入式C高階筆記 結構體

在實際的處理物件中,有許多資訊是由多個不同型別的資料組合在一起進行描述,而且這些不同型別的資料是互相聯絡組成了乙個有機的整體。此時,就要用到一種新的構造型別資料 結構體 structure 簡稱結構。定義乙個結構型別的一般形式為 struct 結構體名 結構體屬於c語言的一種資料型別,與整型 實型相...

C 結構體自定義排序

宣告 本機無c 環境,以下 均沒有編譯測試,最近golang寫的比較多,語法可能會有問題,請自行測試 sort排序函式簡單使用 include using namespace std int a 100 bool cmp1 int x,int y bool cmp2 int x,int y int ...