亚洲综合图片区自拍_思思91精品国产综合在线观看_一区二区三区欧美_欧美黑人又粗又大_亚洲人成精品久久久久桥本

嵌入式多態(tài)原理詳解_環(huán)球焦點(diǎn)

2023-06-19 10:27:14 來(lái)源:CSDN-HiveIOE

引言

在我們的嵌入式C 開(kāi)發(fā)中經(jīng)常會(huì)面對(duì)這樣的一類(lèi)需求:因?yàn)閷?duì)接的設(shè)備支持的協(xié)議不同,自身的設(shè)備需要兼容這些協(xié)議,因此需要業(yè)務(wù)支持不同的協(xié)議解析方式。


(相關(guān)資料圖)

比如有的協(xié)議用 tlv 的數(shù)據(jù)格式,有的用 xml 的格式,有些又用 json 這樣的格式,面對(duì)如此多差異化的需求,我們?cè)撊绾谓鉀Q呢?

一種常見(jiàn)的做法是將協(xié)議解析和邏輯實(shí)現(xiàn)做到一起,每種協(xié)議對(duì)應(yīng)一套代碼,這種實(shí)現(xiàn)方式簡(jiǎn)單,沒(méi)有什么設(shè)計(jì)可言,就是擼代碼。

但是每當(dāng)對(duì)接一種新的協(xié)議就要從頭開(kāi)發(fā),這種重復(fù)造輪子的方式非常初級(jí),代碼的可擴(kuò)展性也非常差,有沒(méi)有一種更高級(jí)一點(diǎn)的方法呢?

答案是有的,也就是我們本文要講的嵌入式多態(tài)。

嵌入式多態(tài)原理

我們首先審視一下上面的需求,上述需求的特點(diǎn)是協(xié)議是有多種的數(shù)據(jù)承載格式(tlv/json/xml),需要針對(duì)不同的協(xié)議做解析,但是解析完成后的數(shù)據(jù)處理,也就是業(yè)務(wù)邏輯的部分卻可以保持不變。

因此我們完全可以使用一種模型將這兩者分離開(kāi)來(lái),將易變的協(xié)議解析部分單獨(dú)作為一個(gè)模塊,將不易變的業(yè)務(wù)邏輯作為一個(gè)模塊。

協(xié)議解析模塊主要負(fù)責(zé)生成數(shù)據(jù),而業(yè)務(wù)邏輯模塊就主要對(duì)數(shù)據(jù)進(jìn)行處理,中間鏈接這兩者的模型,我們暫且稱(chēng)之為數(shù)據(jù)分發(fā)模型,負(fù)責(zé)將協(xié)議解析出的數(shù)據(jù)傳給業(yè)務(wù)邏輯部分。

這樣一來(lái)協(xié)議解析模塊就可以在自己內(nèi)部做任何變化,可以對(duì)不同格式的協(xié)議進(jìn)行解析,而這對(duì)于業(yè)務(wù)邏輯來(lái)說(shuō)都是不感知的,代碼的擴(kuò)展性更佳。

要想達(dá)到這種良好的可擴(kuò)展性,我們引入了一個(gè)負(fù)責(zé)數(shù)據(jù)分發(fā)的模型,這個(gè)模型要怎么實(shí)現(xiàn)呢?

我們看到協(xié)議解析其實(shí)是有多種實(shí)現(xiàn)方式,而業(yè)務(wù)邏輯可以看作只有一種實(shí)現(xiàn)方式,這就是一種多對(duì)一的方式。

在數(shù)據(jù)分發(fā)模型中,負(fù)責(zé)將多種協(xié)議解析方式收斂成一種,我們想一下C語(yǔ)言中哪種方式可以實(shí)現(xiàn)這種多對(duì)一的收斂呢?沒(méi)錯(cuò),就是函數(shù)指針。

這是指針的一種非常高級(jí)的應(yīng)用,它可以將函數(shù)的框架抽象出來(lái),用指針的方式進(jìn)行定義,我們知道指針可以初始化指向不同的地址,那函數(shù)指針就可以被指向多個(gè)不同的函數(shù)。

當(dāng)我們調(diào)用函數(shù)指針時(shí),就可以動(dòng)態(tài)地切換到不同的函數(shù)實(shí)現(xiàn)上。想一下,雖然協(xié)議解析的方式不同,但是最終業(yè)務(wù)邏輯需要的數(shù)據(jù)是固定的,因此完全可以將函數(shù)的參數(shù)搞成一樣的結(jié)構(gòu)。

在面向?qū)ο蟮?u>編程語(yǔ)言中,這種實(shí)現(xiàn)方式稱(chēng)之為多態(tài),同一個(gè)接口(抽象級(jí),沒(méi)有具體實(shí)現(xiàn))可以支持不同的具體實(shí)現(xiàn)。在我們嵌入式C開(kāi)發(fā)中需要自己寫(xiě)這種多態(tài)的接口,但是也不難,筆者將一個(gè)模板寫(xiě)在了下一節(jié)中,讀者可以參照這種寫(xiě)法,靈活修改。

嵌入式多態(tài)偽代碼實(shí)現(xiàn)模板

定義數(shù)據(jù)分發(fā)的模型,抽象接口

1)偽代碼

/*回調(diào)的函數(shù)鉤子*/typedefint(*hook_func)(void*,int,void*);typedefstruct{/*初始化接口,定義諸如內(nèi)存之類(lèi)的問(wèn)題*/void(*init)(void);/*注冊(cè)服務(wù)對(duì)應(yīng)的處理函數(shù),如協(xié)議解析后的業(yè)務(wù)邏輯處理映射*/int(*register)(inttype,hook_funcfunc);/*將數(shù)據(jù)分發(fā)到對(duì)應(yīng)的服務(wù)*/int(*distribute)(void*input,intlen,void*ret);}demo_param_s;

2)代碼解析

在這個(gè)結(jié)構(gòu)體中,我們定義了三個(gè)函數(shù)指針,分別是:

初始化接口,用來(lái)初始化內(nèi)存之類(lèi),這個(gè)內(nèi)存可以用來(lái)存儲(chǔ)我們提供的服務(wù)類(lèi)型和回調(diào)函數(shù);

注冊(cè)服務(wù)處理函數(shù),主要用來(lái)建立服務(wù)類(lèi)型和回調(diào)函數(shù)的映射,在我們的案例中主要將協(xié)議解析后,需要使用哪種業(yè)務(wù)邏輯處理,建立這樣的一個(gè)模型;

數(shù)據(jù)分發(fā)服務(wù),主要將協(xié)議解析后的數(shù)據(jù)作為參數(shù),在服務(wù)映射表中找到對(duì)應(yīng)的回調(diào)函數(shù),然后進(jìn)行回調(diào)。

如下圖所示,可以非常詳細(xì)的描述這個(gè)過(guò)程。

數(shù)據(jù)分發(fā)模型的初始化接口

1)偽代碼

demo_param_s*g_demo_param=NULL;voiddemo_init(constdemo_param_s*param){g_demo_param=param;return;}

2)代碼解析

上面的這部分代碼非常簡(jiǎn)單,首先是定義了一個(gè)全局變量,這個(gè)全局編碼是數(shù)據(jù)分發(fā)模型的類(lèi)型,用來(lái)指向一個(gè)數(shù)據(jù)分發(fā)模型的具體實(shí)現(xiàn),初始時(shí),可以讓這個(gè)全局變量指向空。

接下來(lái),就是定義了一個(gè)初始化接口,這個(gè)接口是來(lái)初始化我們定義的這個(gè)全局變量的,你會(huì)看到這個(gè)全局變量指向了一個(gè)輸入進(jìn)來(lái)的參數(shù),而這個(gè)參數(shù)就是數(shù)據(jù)分發(fā)模型中各個(gè)函數(shù)指針的具體實(shí)現(xiàn)函數(shù),你將在下一節(jié)中看到。

每個(gè)函數(shù)指針的具體實(shí)現(xiàn)

1)偽代碼

voidinit_impl(void);intregister_impl(inttype,hook_funcfunc);intdistribute_impl(void*input,intlen,void*ret);demo_param_sdemo_param={.init=init_impl,.register=register_impl,.distribute=distribute_impl};demo_init(&demo_param);

2)代碼解析

這部分的偽代碼主要是對(duì)3個(gè)函數(shù)指針實(shí)現(xiàn),并進(jìn)行初始化。

首先是三個(gè)具體的實(shí)現(xiàn)函數(shù)被聲明和定義,第一個(gè)初始化函數(shù),就是 malloc 出內(nèi)存;第二個(gè)函數(shù),建立服務(wù)和業(yè)務(wù)處理函數(shù)的映射關(guān)系;第三個(gè)函數(shù),在需要某種服務(wù)時(shí),通過(guò)查詢(xún)第二個(gè)函數(shù)建立的映射表,回調(diào)具體的業(yè)務(wù);

其次就是定義了一個(gè)數(shù)據(jù)分發(fā)模型的局部變量,然后初始化其中的每個(gè)函數(shù)指針;

最后調(diào)用我們?cè)谇懊娑x的數(shù)據(jù)分發(fā)初始化接口,將上面定義的局部變量的值傳入,使其可以全局訪(fǎng)問(wèn),在后面我們就可以直接用全局變量 g_demo_param 加上其中的參數(shù)的方式調(diào)用每個(gè)接口。

通過(guò)抽象接口調(diào)用注冊(cè)和分發(fā)功能

1)偽代碼

//分發(fā)for(i=0;i
//注冊(cè)inttype=0;intlogic_func(void*input,intlen,void*ret);ret=g_demo_param.register(type,logic_func);

2)代碼解析

上面就是我們的注冊(cè)和分發(fā)的接口,其中注冊(cè)的部分是在業(yè)務(wù)邏輯中實(shí)現(xiàn)的,分發(fā)的部分代碼是在協(xié)議解析的部分實(shí)現(xiàn)的。

需要特別注意這個(gè)實(shí)現(xiàn)規(guī)則,因?yàn)橹挥羞@樣才能達(dá)到業(yè)務(wù)邏輯和協(xié)議解析的分離,協(xié)議解析只依賴(lài)我們的數(shù)據(jù)分發(fā)模型,業(yè)務(wù)邏輯也只依賴(lài)我們的數(shù)據(jù)分發(fā)模型,這兩者之間互不依賴(lài),可以獨(dú)立的編譯或者打包。

首先我們看注冊(cè),有類(lèi)型和具體函數(shù)實(shí)現(xiàn),我們可以使用 g_demo_param.register 去創(chuàng)建兩者的映射關(guān)系,將其保存在內(nèi)存中。

然后當(dāng)我們解析完協(xié)議,就來(lái)到我們的分發(fā)部分,當(dāng)我們的類(lèi)型在內(nèi)存映射表中有存儲(chǔ)時(shí),就可以使用g_demo_param.distribute 實(shí)現(xiàn)分發(fā),調(diào)用我們的業(yè)務(wù)邏輯代碼。

小結(jié)

隨著嵌入式軟件變得越來(lái)越復(fù)雜,架構(gòu)問(wèn)題也變得越來(lái)越突出,市場(chǎng)上我們最多見(jiàn)的是對(duì)互聯(lián)網(wǎng)這類(lèi)架構(gòu)的介紹,鮮有專(zhuān)門(mén)針對(duì)嵌入式軟件的架構(gòu)分析。本文通過(guò)一個(gè)案例淺談了嵌入式多態(tài)的實(shí)現(xiàn)方式,目的是幫助讀者在設(shè)計(jì)開(kāi)發(fā)相關(guān)的場(chǎng)景時(shí)能夠拿來(lái)借鑒,使自己的代碼具有更好地?cái)U(kuò)展性。

審核編輯:湯梓紅

標(biāo)簽:

上一篇:RISC-V vector intrinsic編程入門(mén)指南
下一篇:最后一頁(yè)