嵌入式軟件架構(gòu)設(shè)計-函數(shù)調(diào)用
掃描二維碼
隨時隨地手機看文章
1、前言
函數(shù)調(diào)用很好理解,即使剛學(xué)沒多久的朋友也知道函數(shù)調(diào)用是怎么實現(xiàn)的,即調(diào)用一個已經(jīng)封裝好的函數(shù),實現(xiàn)某個特定的功能。
把一個或者多個功能通過函數(shù)的方式封裝起來,對外只提供一個簡單的函數(shù)接口,然后在其他地方調(diào)用即可
2、函數(shù)調(diào)用方式
函數(shù)調(diào)用難道還能怎么調(diào)用?不就封裝好直接調(diào)用嗎???
函數(shù)調(diào)用方式分為兩種:直接調(diào)用和間接調(diào)用
直接調(diào)用
直接調(diào)用就是我們平常使用的方式,下面的方式就屬于直接調(diào)用了。
int SumFun(int a, int b) { return a + b; } int main() { // 直接調(diào)用定義好的函數(shù) int sum = SumFun(5, 6); printf("sum=%d", sum); return 0; }
間接調(diào)用
間接調(diào)用在初學(xué)時很難使用到,這是通過函數(shù)指針的方式實現(xiàn)的。
函數(shù)指針本質(zhì)是一個指針變量,是一個指向函數(shù)的指針(函數(shù)本身也是有地址的,指向的是函數(shù)入口);
而指針函數(shù)本質(zhì)是一個函數(shù),其返回值為指針。
函數(shù)指針的用法如下:
typedef int (*FunctionCB)(int, int); int SumFun(int a, int b) { return a + b; } int main() { // 將定義好的函數(shù)賦值給函數(shù)指針 FunctionCB pfnSum = SumFun; // 通過函數(shù)指針間接調(diào)用 int sum = pfnSum(5, 6); printf("sum=%d", sum); return 0; }
3、什么場景使用
函數(shù)指針在軟件架構(gòu)分層設(shè)計中十分重要,因為分層設(shè)計中有一個設(shè)計原則,那就是下層函數(shù)不能直接調(diào)用上層函數(shù),那么可以通過函數(shù)指針的方式實現(xiàn);一般稱上層通過函數(shù)指針賦值給下層的函數(shù)為回調(diào)函數(shù)。
什么情況會存在需要下層程序需要調(diào)用上層程序的呢?
比如串口數(shù)據(jù)接收,雖然可以通過查詢的方式接收,但是遠不及通過串口中斷的方式接收及時,當(dāng)接收完成時,需要立即通知上層讀取數(shù)據(jù)進行處理,而不是等待上層程序查詢讀取。
如何實現(xiàn)呢?
比如硬件抽象層/驅(qū)動層中的串口模塊實現(xiàn)函數(shù)
/************* UART.c 文件 ****************/ static UartRecvCB sg_pfnUartRecv; // 設(shè)置數(shù)據(jù)幀接收處理回調(diào)函數(shù) void UART_SetRecvCallback(UartRecvCB pfnUartRecv) { sg_pfnUartRecv = pfnUartRecv; } void UART_Task(void) { if (RecvEnd) { // 數(shù)據(jù)一幀接收完成立即調(diào)用 if (sg_pfnUartRecv != NULL) { sg_pfnUartRecv(UartRecvBuf, UartRecvLength); } } } /************* UART.h 文件 ****************/ typedef void (*UartRecvCB)(const char *, int); extern void UART_SetRecvCallback(UartRecvCB pfnUartRecv); extern void UART_Task(void);
應(yīng)用層代碼中實現(xiàn)回調(diào)函數(shù),并調(diào)用下層函數(shù)。
// 回調(diào)函數(shù):串口數(shù)據(jù)處理 void OnUartRecvProcess(const char *pBuf, int length) { // 處理串口數(shù)據(jù) printf("Recv: %s", pBuf); } int main() { UART_SetRecvCallback(OnUartRecvProcess); while(1) { if (TimeFlag) { UART_Task(); } } }
上述示例中通過函數(shù)指針的方式間接調(diào)用了應(yīng)用層的函數(shù),而且并不違背分層設(shè)計原則。
如果看代碼不能立即理解的話,可以嘗試通過下圖理解:





