色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

了解一下函數指針的概念和使用方法

嵌入式情報局 ? 來源:嵌入式情報局 ? 2023-11-06 10:04 ? 次閱讀

一、函數指針

在講回調函數之前,我們需要了解函數指針。

我們都知道,C語言的靈魂是指針,我們經常使用整型指針,字符串指針,結構體指針等。

int*p1;
char*p2;
STRUCT*p3;// STRUCT為我們定義的結構體

但是好像我們一般很少使用函數指針,我們一般使用函數都是直接使用函數調用。

下面我們來了解一下函數指針的概念和使用方法。

1. 概念

函數指針是指向函數的指針變量。

通常我們說的指針變量是指向一個整型、字符型或數組等變量,而函數指針是指向函數。

函數指針可以像一般函數一樣,用于調用函數、傳遞參數

函數指針的定義方式為:

函數返回值類型 (* 指針變量名) (函數參數列表);

“函數返回值類型”表示該指針變量可以指向具有什么返回值類型的函數;“函數參數列表”表示該指針變量可以指向具有什么參數列表的函數。這個參數列表中只需要寫函數的參數類型即可。

我們看到,函數指針的定義就是將“函數聲明”中的“函數名”改成“(指針變量名)”。但是這里需要注意的是:“(指針變量名)”兩端的括號不能省略,括號改變了運算符的優先級。如果省略了括號,就不是定義函數指針而是一個函數聲明了,即聲明了一個返回值類型為指針型的函數。

那么怎么判斷一個指針變量是指向變量的指針變量還是指向函數的指針變量呢?首先看變量名前面有沒有“”,如果有“”說明是指針變量;其次看變量名的后面有沒有帶有形參類型的圓括號,如果有就是指向函數的指針變量,即函數指針,如果沒有就是指向變量的指針變量。

最后需要注意的是,指向函數的指針變量沒有 ++ 和 – 運算。

一般為了方便使用,我們會選擇:

typedef 函數返回值類型 (* 指針變量名) (函數參數列表);

比如:

typedefint(*Fun1)(int);//聲明也可寫成int (*Fun1)(int x),但習慣上一般不這樣。
typedefint(*Fun2)(int,int);//參數為兩個整型,返回值為整型
typedefvoid(*Fun3)(void);//無參數和返回值
typedefvoid*(*Fun4)(void*);//參數和返回值都為void*指針

2. 如何用函數指針調用函數

給大家舉一個例子:

intFunc(intx);/*聲明一個函數*/
int(*p)(intx);/*定義一個函數指針*/
p=Func;/*將Func函數的首地址賦給指針變量p*/
p=&Func;/*將Func函數的首地址賦給指針變量p*/

賦值時函數 Func 不帶括號,也不帶參數。由于函數名 Func 代表函數的首地址,因此經過賦值以后,指針變量 p 就指向函數 Func() 代碼的首地址了。

下面來寫一個程序,看了這個程序你們就明白函數指針怎么使用了:

#include
intMax(int,int);//函數聲明
intmain(void)
{
int(*p)(int,int);//定義一個函數指針
inta,b,c;
p=Max;//把函數Max賦給指針變量p,使p指向Max函數
printf("pleaseenteraandb:");
scanf("%d%d",&a,&b);
c=(*p)(a,b);//通過函數指針調用Max函數
printf("a=%d
b=%d
max=%d
",a,b,c);
return0;
}
intMax(intx,inty)//定義Max函數
{
intz;
if(x>y)
{
z=x;
}
else
{
z=y;
}
returnz;
}

特別注意的是,因為函數名本身就可以表示該函數地址(指針),因此在獲取函數指針時,可以直接用函數名,也可以取函數的地址。

p=Max可以改成p=&Max
c=(*p)(a,b)可以改成c=p(a,b)

3. 函數指針作為某個函數的參數

既然函數指針變量是一個變量,當然也可以作為某個函數的參數來使用的。示例:

#include
#include

typedefvoid(*FunType)(int);
//前加一個typedef關鍵字,這樣就定義一個名為FunType函數指針類型,而不是一個FunType變量。
//形式同typedefint*PINT;
voidmyFun(intx);
voidhisFun(intx);
voidherFun(intx);
voidcallFun(FunTypefp,intx);
intmain()
{
callFun(myFun,100);//傳入函數指針常量,作為回調函數
callFun(hisFun,200);
callFun(herFun,300);

return0;
}

voidcallFun(FunTypefp,intx)
{
fp(x);//通過fp的指針執行傳遞進來的函數,注意fp所指的函數有一個參數
}

voidmyFun(intx)
{
printf("myFun:%d
",x);
}
voidhisFun(intx)
{
printf("hisFun:%d
",x);
}
voidherFun(intx)
{
printf("herFun:%d
",x);
}

輸出:

9e43e9a6-7b0e-11ee-939d-92fbcf53809c.jpg

4. 函數指針作為函數返回類型

有了上面的基礎,要寫出返回類型為函數指針的函數應該不難了,下面這個例子就是返回類型為函數指針的函數:

void(*func5(int,int,float))(int,int)
{
...
}

在這里,func5以(int, int, float)為參數,其返回類型為void (*)(int, int)。在C語言中,變量或者函數的聲明也是一個大學問,想要了解更多關于聲明的話題,可以參考我之前的文章 - C專家編程》讀書筆記(1-3章)。這本書的第三章花了整整一章的內容來講解如何讀懂C語言的聲明。

5. 函數指針數組

在開始講解回調函數前,最后介紹一下函數指針數組。既然函數指針也是指針,那我們就可以用數組來存放函數指針。下面我們看一個函數指針數組的例子:

/*方法1*/
void(*func_array_1[5])(int,int,float);

/*方法2*/
typedefvoid(*p_func_array)(int,int,float);
p_func_arrayfunc_array_2[5];

上面兩種方法都可以用來定義函數指針數組,它們定義了一個元素個數為5,類型是 *void (*)(int, int, float) *的函數指針數組。

6. 函數指針總結

函數指針常量 :Max;函數指針變量:p;

數名調用如果都得如(*myFun)(10)這樣,那書寫與讀起來都是不方便和不習慣的。所以C語言的設計者們才會設計成又可允許myFun(10)這種形式地調用(這樣方便多了,并與數學中的函數形式一樣)。

在函數指針變量也可以存入一個數組內。數組的聲明方法:int (*fArray[10]) ( int );

二、回調函數

1. 什么是回調函數

我們先來看看百度百科是如何定義回調函數的:

回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。

這段話比較長,也比較繞口。下面我通過一幅圖來說明什么是回調:

9e564e70-7b0e-11ee-939d-92fbcf53809c.png

假設我們要使用一個排序函數來對數組進行排序,那么在主程序(Main program)中,我們先通過庫,選擇一個庫排序函數(Library function)。但排序算法有很多,有冒泡排序,選擇排序,快速排序,歸并排序。同時,我們也可能需要對特殊的對象進行排序,比如特定的結構體等。庫函數會根據我們的需要選擇一種排序算法,然后調用實現該算法的函數來完成排序工作。這個被調用的排序函數就是回調函數(Callback function)。

結合這幅圖和上面對回調函數的解釋,我們可以發現,要實現回調函數,最關鍵的一點就是要將函數的指針傳遞給一個函數(上圖中是庫函數),然后這個函數就可以通過這個指針來調用回調函數了。注意,回調函數并不是C語言特有的,幾乎任何語言都有回調函數。在C語言中,我們通過使用函數指針來實現回調函數。

我的理解是:把一段可執行的代碼像參數傳遞那樣傳給其他代碼,而這段代碼會在某個時刻被調用執行,這就叫做回調。

如果代碼立即被執行就稱為同步回調,如果過后再執行,則稱之為異步回調。

回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。

回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。

2. 為什么要用回調函數?

因為可以把調用者與被調用者分開,所以調用者不關心誰是被調用者。它只需知道存在一個具有特定原型和限制條件的被調用函數。

簡而言之,回調函數就是允許用戶把需要調用的方法的指針作為參數傳遞給一個函數,以便該函數在處理相似事件的時候可以靈活的使用不同的方法。

9e637a0a-7b0e-11ee-939d-92fbcf53809c.jpg

intCallback()// /

回調似乎只是函數間的調用,和普通函數調用沒啥區別。

但仔細看,可以發現兩者之間的一個關鍵的不同:在回調中,主程序把回調函數像參數一樣傳入庫函數。

這樣一來,只要我們改變傳進庫函數的參數,就可以實現不同的功能,這樣有沒有覺得很靈活?并且當庫函數很復雜或者不可見的時候利用回調函數就顯得十分優秀。

3. 怎么使用回調函數?

intCallback_1(inta)// /

如上述代碼:可以看到,Handle()函數里面的參數是一個指針,在main()函數里調用Handle()函數的時候,給它傳入了函數Callback_1()/Callback_2()/Callback_3()的函數名,這時候的函數名就是對應函數的指針,也就是說,回調函數其實就是函數指針的一種用法。

4. 下面是一個四則運算的簡單回調函數例子:

#include
#include

/****************************************
*函數指針結構體
***************************************/
typedefstruct_OP{
float(*p_add)(float,float);
float(*p_sub)(float,float);
float(*p_mul)(float,float);
float(*p_div)(float,float);
}OP;

/****************************************
*加減乘除函數
***************************************/
floatADD(floata,floatb)
{
returna+b;
}

floatSUB(floata,floatb)
{
returna-b;
}

floatMUL(floata,floatb)
{
returna*b;
}

floatDIV(floata,floatb)
{
returna/b;
}

/****************************************
*初始化函數指針
***************************************/
voidinit_op(OP*op)
{
op->p_add=ADD;
op->p_sub=SUB;
op->p_mul=&MUL;
op->p_div=÷
}

/****************************************
*庫函數
***************************************/
floatadd_sub_mul_div(floata,floatb,float(*op_func)(float,float))
{
return(*op_func)(a,b);
}

intmain(intargc,char*argv[])
{
OP*op=(OP*)malloc(sizeof(OP));
init_op(op);

/*直接使用函數指針調用函數*/
printf("ADD=%f,SUB=%f,MUL=%f,DIV=%f
",(op->p_add)(1.3,2.2),(*op->p_sub)(1.3,2.2),
(op->p_mul)(1.3,2.2),(*op->p_div)(1.3,2.2));

/*調用回調函數*/
printf("ADD=%f,SUB=%f,MUL=%f,DIV=%f
",
add_sub_mul_div(1.3,2.2,ADD),
add_sub_mul_div(1.3,2.2,SUB),
add_sub_mul_div(1.3,2.2,MUL),
add_sub_mul_div(1.3,2.2,DIV));

return0;
}

5. 回調函數實例(很有用)

一個GPRS模塊聯網的小項目,使用過的同學大概知道2G、4G、NB等模塊要想實現無線聯網功能都需要經歷模塊上電初始化、注冊網絡、查詢網絡信息質量、連接服務器等步驟,這里的的例子就是,利用一個狀態機函數(根據不同狀態依次調用不同實現方法的函數),通過回調函數的方式依次調用不同的函數,實現模塊聯網功能,如下:

/*********工作狀態處理*********/
typedefstruct
{
uint8_tmStatus;
uint8_t(*Funtion)(void);//函數指針的形式
}M26_WorkStatus_TypeDef;//M26的工作狀態集合調用函數


/**********************************************
**>M26工作狀態集合函數
***********************************************/
M26_WorkStatus_TypeDefM26_WorkStatus_Tab[]=
{
{GPRS_NETWORK_CLOSE,M26_PWRKEY_Off},//模塊關機
{GPRS_NETWORK_OPEN,M26_PWRKEY_On},//模塊開機
{GPRS_NETWORK_Start,M26_Work_Init},//管腳初始化
{GPRS_NETWORK_CONF,M26_NET_Config},//AT指令配置
{GPRS_NETWORK_LINK_CTC,M26_LINK_CTC},//連接調度中心
{GPRS_NETWORK_WAIT_CTC,M26_WAIT_CTC},//等待調度中心回復
{GPRS_NETWORK_LINK_FEM,M26_LINK_FEM},//連接前置機
{GPRS_NETWORK_WAIT_FEM,M26_WAIT_FEM},//等待前置機回復
{GPRS_NETWORK_COMM,M26_COMM},//正常工作
{GPRS_NETWORK_WAIT_Sig,M26_WAIT_Sig},//等待信號回復
{GPRS_NETWORK_GetSignal,M26_GetSignal},//獲取信號值
{GPRS_NETWORK_RESTART,M26_RESET},//模塊重啟
}
/**********************************************
**>M26模塊工作狀態機,依次調用里面的12個函數
***********************************************/
uint8_tM26_WorkStatus_Call(uint8_tStart)
{
uint8_ti=0;
for(i=0;i

所以,如果有人想做個NB模塊聯網項目,可以copy上面的框架,只需要修改回調函數內部的具體實現,或者增加、減少回調函數,就可以很簡潔快速的實現模塊聯網。







審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5090

    文章

    19176

    瀏覽量

    306883
  • GPRS
    +關注

    關注

    21

    文章

    984

    瀏覽量

    129566
  • C語言
    +關注

    關注

    180

    文章

    7614

    瀏覽量

    137421
  • 狀態機
    +關注

    關注

    2

    文章

    492

    瀏覽量

    27615
  • 回調函數
    +關注

    關注

    0

    文章

    87

    瀏覽量

    11607

原文標題:嵌入式編程先搞定回調函數

文章出處:【微信號:嵌入式情報局,微信公眾號:嵌入式情報局】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    淺析函數指針指針函數及其應用

    什么是指針?相信大家對這個問題其實并不陌生,對指針概念也不會很模糊,在這里我也大概介紹一下
    發表于 03-08 13:17 ?288次閱讀

    函數指針指針函數概念

    不少朋友會混淆“函數指針”和“指針函數”這兩個概念,本文詳細介紹一下
    發表于 03-09 10:49 ?1235次閱讀

    linux系統中常見注冊函數使用方法

    大家好,今天給大家分享一下,linux系統中常見的注冊函數register_chrdev_region()、register_chrdev()、 alloc_chrdev_region()的使用方法
    發表于 10-19 09:28 ?653次閱讀
    linux系統中常見注冊<b class='flag-5'>函數</b>的<b class='flag-5'>使用方法</b>

    C51語言的指針、結構、聯合和枚舉

     指針是C51語言的精華也是難點。本章主要介紹指針概念、定義指針方法,介紹指向
    發表于 06-12 23:47 ?112次下載

    函數指針指針函數定義

    函數指針指針函數,C語言學習中最容易混淆的概念,好好學習吧
    發表于 01-11 16:44 ?0次下載

    c語言函數指針定義,指針函數函數指針的區別

     往往,我們提到指針函數函數指針的時候,就有很多人弄不懂。下面就由小編詳細為大家介紹C語言中函數
    發表于 11-16 15:18 ?3634次閱讀

    vlookup函數使用方法及實例

    VLOOKUP函數是EXCEL最常用的查找函數,VLOOKUP函數欄目有很多該函數的各種使用方法的教程,但還是有很多同學提問與該
    發表于 12-01 16:27 ?6.6w次閱讀
    vlookup<b class='flag-5'>函數</b><b class='flag-5'>使用方法</b>及實例

    簡要介紹一下Python-UNO的使用方法

    OpenOffice是個免費的、開源的辦公套裝,集成了允許開發者用不同語言進行開發的API。Python-UNO讓你可以在Python環境使用OpenOffice。本文簡要介紹了一下Python-UNO的
    的頭像 發表于 01-04 14:54 ?8691次閱讀
    簡要介紹<b class='flag-5'>一下</b>Python-UNO的<b class='flag-5'>使用方法</b>

    理解函數指針函數指針數組、函數指針數組的指針

    理解函數指針函數指針數組、函數指針數組的指針
    的頭像 發表于 06-29 15:38 ?1.5w次閱讀
    理解<b class='flag-5'>函數</b><b class='flag-5'>指針</b>、<b class='flag-5'>函數</b><b class='flag-5'>指針</b>數組、<b class='flag-5'>函數</b><b class='flag-5'>指針</b>數組的<b class='flag-5'>指針</b>

    函數指針和回調函數使用方法

    了解開發語言的朋友應該都會對回調函數有所了解,在很多的程序開發語言中都能看到回調的身影。很多場景,當某個條件成立以后我們希望代碼執行某些指定的部分,這個時候可以考慮使用回調
    的頭像 發表于 04-10 15:08 ?1175次閱讀

    C語言進階:函數指針概念使用方法

    函數指針是指向函數指針變量。 通常我們說的指針變量是指向個整型、字符型或數組等變量,而
    發表于 05-02 06:17 ?5929次閱讀

    分享一下STM32基于CubeMX獨立看門狗的使用方法

    項目里面需要加個獨立看門狗,就上網了解一下,具體原理后期有時間再分享,今天先簡單分享一下使用方法
    的頭像 發表于 10-26 14:38 ?3531次閱讀
    分享<b class='flag-5'>一下</b>STM32基于CubeMX獨立看門狗的<b class='flag-5'>使用方法</b>

    函數指針的基本概念和語法

    函數指針種非常強大的編程工具,它可以讓我們以更加靈活的方式編寫程序。在本文中,我們將介紹 8 個函數指針的高級應用場景,并貼出相應的代碼
    的頭像 發表于 12-12 09:33 ?478次閱讀

    函數指針指針函數是不是個東西?

    函數指針的本質是指針,就跟整型指針、字符指針樣,函數
    的頭像 發表于 01-03 16:35 ?547次閱讀
    <b class='flag-5'>函數</b><b class='flag-5'>指針</b>和<b class='flag-5'>指針</b><b class='flag-5'>函數</b>是不是<b class='flag-5'>一</b>個東西?

    面試常考+1:函數指針指針函數、數組指針指針數組

    在嵌入式開發領域,函數指針指針函數、數組指針指針數組是
    的頭像 發表于 08-10 08:11 ?976次閱讀
    面試常考+1:<b class='flag-5'>函數</b><b class='flag-5'>指針</b>與<b class='flag-5'>指針</b><b class='flag-5'>函數</b>、數組<b class='flag-5'>指針</b>與<b class='flag-5'>指針</b>數組
    主站蜘蛛池模板: 97资源站超碰在线视频 | 麻豆成人久久精品二区三区网站 | 蜜桃成熟时33D在线嘟嘟网 | 亚洲精品无码不卡在线播HE | 久久久久久久久久毛片精品美女 | 国产成人无码精品久久久按摩 | 成人手机在线观看 | 国产一级毛片在线 | 国产性夜夜性夜夜爽91 | 你的欲梦裸身在线播放 | 亚洲AV无码乱码国产精品品麻豆 | 激情女人花 | 伦理片在线线手机版韩国免费观看 | 2017欧美狠狠色 | 国产免费内射又粗又爽密桃视频 | 色偷偷亚洲男人天堂 | 在线亚洲色拍偷拍在线视频 | 亚洲区视频 | 日本女人bbb | 亚洲国产欧美另类 | 香蕉 在线播放 | 国产乱国产乱老熟300部视频 | 国产精品高潮AV久久无码 | 伊人久久精品AV一区二区 | 国产精品嫩草影视在线观看 | 国产高清视频在线观看不卡v | 久久国产香蕉视频 | 国产午夜永久福利视频在线观看 | 芳草地在线观看免费视频 | 精品久久伦理中文字幕 | 中文无码不卡的岛国片国产片 | 亚洲精品AV无码喷奶水糖心 | 久久午夜夜伦痒痒想咳嗽P 久久午夜夜伦鲁鲁片无码免费 | china年轻小帅脸直播飞机 | 琪琪伦伦影院理论片 | 欧美肥胖女人bbwbbw视频 | 日本xxxxxx片免费播放18 | 日本动漫henta videos | 国产精品久久久久AV麻豆 | 午夜伦理yy44008影院 | 中文字幕高清在线中文字幕 |