91视频免费?看_蜜芽MY188精品TV在线观看_国产免费无遮挡在线观看视频_深夜国产_亚洲精品欧洲精品_欧美黑人粗暴多交

STM32編程:void指針高階用法舉例,設(shè)計一個通用掉電存儲子系統(tǒng)

[導讀] 要比較靈活的使用C語言實現(xiàn)一些高層級的框架時,需要掌握一些進階編程技巧,這篇來談?wù)剉oid指針的一些妙用。測試環(huán)境采用 IAR for ARM 8.40.1

什么是void指針?

void指針一般被稱為通用指針或叫泛指針。它是C語言關(guān)于純粹地址的一種約定。當某個指針是void型指針時,所指向的對象不屬于任何類型。 因為void指針不屬于任何類型,則不可以對其進行算術(shù)運算,比如自增,編譯器不知道其自增需要增加多少。比如char *型指針,自增一定是指針指向的地址加1,short *型指針自增,則偏移2。

在C/C++中,在任意時刻都可以使用其它類型指針來代替void指針,或者用void指針來代替其他類型指針。由這些特性就可以衍生出很多比較有用的技巧。指針的本質(zhì),是其值為一個地址,那么延伸一下:

當使用關(guān)鍵字void聲明指針變量時,它將成為通用指針變量。 任何數(shù)據(jù)類型(char,int,float等)的任何變量的地址都可以賦值給void指針變量。

對指針變量的解引用,使用間接運算符*達到目的。 但是在使用空指針的情況下,需要轉(zhuǎn)換指針變量以解引用。 這是因為空指針沒有與之關(guān)聯(lián)的數(shù)據(jù)類型。 編譯器無法知道void指針指向的數(shù)據(jù)類型。 因此,要獲取由void指針指向的數(shù)據(jù),需要使用在void指針位置內(nèi)保存的正確類型的數(shù)據(jù)進行類型轉(zhuǎn)換。

對于空指針的解引用,你如不信,就來看看栗子:

看到了吧,直接解引用編譯不過,因為編譯器蒙了。

但須注意的是:

  • 不同的編譯器對void指針處理是不一樣的,如IAR,ANSI C,VC對上述都將出錯,而GNU指定“void”的算法操作與“char”一致,因此上述寫法在GNU則可以編譯

所以做個類型轉(zhuǎn)換,修正如下:

  • void型指針解引用須做類型指定。
  • 類型轉(zhuǎn)換的時候須注意類型匹配。

另外,如果函數(shù)類型可以是任意類型的指針,則需將其參數(shù)定義為void *,例如string.h中關(guān)于內(nèi)存操作的函數(shù)集:

  __EFF_NENW1NW2   __ATTRIBUTES   int       memcmp(const void *, const void *,
                                                   size_t);
  __EFF_NENR1NW2R1 __DEPREC_ATTRS void *    memcpy(void *_Restrict,
                                                   const void *_Restrict,
                                                   size_t);
  __EFF_NENR1NW2R1 __DEPREC_ATTRS void *    memmove(void *, const void *,
                                                    size_t);
  __EFF_NENR1R1    __DEPREC_ATTRS void *    memset(void *, int, size_t);

非易失存儲管理應(yīng)用

在單片機開發(fā)中,往往需要實現(xiàn)數(shù)據(jù)的非易失存儲。所謂非易失存儲,就是數(shù)據(jù)改寫后在掉電后仍然能保持。哪些是非易失存儲介質(zhì)呢?比如EEPROM,FLASH等都屬于非易失存儲介質(zhì)。

比如一個產(chǎn)品里面有很多各種各樣的參數(shù),且分布在各個子系統(tǒng)文件中。舉個栗子:

/*模塊A中有這樣一個結(jié)構(gòu)體需要非易失存儲*/
typedef struct _t_paras{
   int language;/*語言種類*/
   char SN[20]; /*產(chǎn)品序列號*/
}T_PARAS;
T_PARAS sysParas;

/*模塊B中有這樣一個結(jié)構(gòu)體需要非易失存儲*/
typedef struct _t_pid{
   float kp;
   float ki;
   float kd;
   float T;
}T_PID;
T_PID pidParas;

面對這樣一個需求,要實現(xiàn)非易失存儲,我在將底層的EEPROM/FLASH讀寫函數(shù)實現(xiàn)的基礎(chǔ)上,將上述應(yīng)用數(shù)據(jù)按照一定順序存儲管理。那么更為理想的方式是什么呢?設(shè)計一個模塊專門負責存儲非易失數(shù)據(jù)。比如:

typedef struct _t_nv_layout{
     void * pElement; /*參數(shù)地址*/
     int    length;   /*參數(shù)長度*/
}T_NV_LAYOUT;
/*參數(shù)映射表*/
T_NV_LAYOUT nvLayout[]={
    {&sysParas,sizeof(T_PARAS)},/*參數(shù)映射記錄*/
    {&pidParas,sizeof(T_PID)},
    ...
};
/*參數(shù)映射表記錄條數(shù)*/
#define NV_RECORD_NUMBER  (sizeof(nvLayout)/sizeof(T_NV_LAYOUT))
void nv_load(T_NV_LAYOUT *pLayout,int nvAddr,int number);
void nv_store(T_NV_LAYOUT *pLayout,int nvAddr,int number);

將上述設(shè)計思想,利用UML描述一下:

在上述基礎(chǔ)上,我們只需要設(shè)計硬件層抽象,即可設(shè)計出一個可行的、比較通用的NV管理子系統(tǒng),這樣設(shè)計出的子系統(tǒng)忽略了業(yè)務(wù)數(shù)據(jù),僅僅將其處理為數(shù)據(jù),并不關(guān)心其業(yè)務(wù)意義。實現(xiàn)了業(yè)務(wù)邏輯與后臺的隔離解耦。做到了通用性。這里就比較巧妙的利用了void *指針的特性。如果對于該設(shè)計思想,在進一步延伸,將底層的抽象在做一層封裝,將更細節(jié)的底層實現(xiàn)細節(jié)隔離抽象,比如:

  • 抽象I2C/SPI EEPROM,將其對上層的調(diào)用接口統(tǒng)一,那么如果你的系統(tǒng)原本是存儲在I2C EEPROM中,現(xiàn)在做一個新項目,你需要使用另外一種SPI接口的EEPROM,則只需要實現(xiàn)相應(yīng)的底層處理函數(shù)即可。
  • 將存儲介質(zhì)抽象,比如是EEPROM/DATA FLASH等...
  • ....

那么怎么做到底層抽象呢,我們可以利用函數(shù)指針定義統(tǒng)一的接口,具體部署時,只需要將實現(xiàn)函數(shù)的指針賦值給對應(yīng)的函數(shù)指針即可,這樣就做到了接口的抽象統(tǒng)一。其實這就是驅(qū)動模型的一個簡易雛形。

總結(jié)一下

這篇文章引入了一些編程思想,對于單片機/嵌入式進階編程比較有用:

  • 利用void *指針,將業(yè)務(wù)數(shù)據(jù)與底層存儲實現(xiàn)了抽象解耦
  • 利用分層抽象實現(xiàn)了代碼具有良好的可移植性
  • 利用函數(shù)指針實現(xiàn)了C++等高級語言的虛函數(shù)定義接口的思想
  • 統(tǒng)一接口底層實現(xiàn)抽象,實現(xiàn)了驅(qū)動分層的思想
  • void *指針由這個例子,可以延伸出很多類似的應(yīng)用

啟示:一些語言細節(jié)如果深入了解其背后的機理,可以得到很多比較巧妙的應(yīng)用。

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 4
收藏 6
關(guān)注 79
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧
主站蜘蛛池模板: 甘德县| 友谊县| 隆回县| 阜宁县| 公安县| 哈密市| 林州市| 婺源县| 台州市| 曲阜市| 富川| 邢台市| 兰西县| 天气| 博爱县| 维西| 武隆县| 海原县| 南丹县| 鹤庆县| 海兴县| 郧西县| 霍林郭勒市| 大关县| 安陆市| 辽源市| 金溪县| 准格尔旗| 留坝县| 双城市| 竹北市| 平顶山市| 固镇县| 富平县| 铁力市| 水城县| 景洪市| 韩城市| 虞城县| 中超| 曲阳县|