初識 typedef void(*Func)(void)
關(guān)注、星標(biāo)公眾號,直達(dá)精彩內(nèi)容
來源:技術(shù)讓夢想更偉大
作者:李肖遙
void (*Fun)(void);假如就只是寫上這樣的一句代碼,顯然這就是定義了一個(gè)變量Fun,這個(gè)Fun變量是一個(gè)指針,指向返回值和參數(shù)都是空的函數(shù)的指針。而typedef void(*Func)(void) 是函數(shù)指針的類型定義,代表了一種新的類型。作用是聲明一個(gè) void(*)()類型的函數(shù)指針Func。這些基礎(chǔ)知識我們一步一步來學(xué)習(xí)了解一下。
typedef/define的基本概念
typedef
為現(xiàn)有類型創(chuàng)建一個(gè)新的名字,基本用法舉例:
typedef unsigned char UCHAR;//右邊代替左邊
typedef能隱藏笨拙的語法構(gòu)造以及平臺一些相關(guān)的數(shù)據(jù)類型,可以使得代碼更美觀,可維護(hù)性、可移植性、可讀性更強(qiáng),來舉個(gè)例子吧。
//定義一個(gè)函數(shù)
void tech(void) { printf("tech dreamer"); }
void main()
{
//定義一個(gè)指針,指針的名字叫func
void (*func)();//tech函數(shù)帶參數(shù)的話也可以
func = &tech; //&可以不加
func(); //第一種調(diào)用方式,帶參數(shù)也可以
(*func)(); //第二種調(diào)用方式,帶參數(shù)也可以
}
為了寫出更加美觀和可讀性強(qiáng)的代碼,我們經(jīng)常使用typedef來定義一個(gè)類型,代碼如下。
void tech(void) { printf("tech dreamer"); }
//命名一個(gè)類型,那么這個(gè)時(shí)候func不可以直接調(diào)用,而是一個(gè)類型了
typedef void (*func)();
void main()
{
//定義一個(gè)可調(diào)用的指針變量(函數(shù)):myfunc
func myfunc;
myfunc = &tech; //&可以不加
myfunc(); //第一種調(diào)用方式,帶參數(shù)也可以
(*myfunc)(); //第二種調(diào)用方式,帶參數(shù)也可以
}
與define的區(qū)別
typedef 是在編譯過程中被解析的,而#define是在編譯之前的預(yù)處理時(shí)被破解的;#define只是對所定義的別名的簡單替換,而typedef可以做到#define能做到的所有事情,而且可以做得更好
函數(shù)指針的基本概念
我們先了解一下函數(shù)指針的基本概念,函數(shù)指針是指向函數(shù)的指針變量,他的本質(zhì)是一個(gè)指針變量,函數(shù)的指針定義:int (*f)(int);
//舉個(gè)例子聲明一個(gè)函數(shù)指針
int (*f)(int x);
f=func; /* 將func函數(shù)的首地址賦給指針f */
與指針函數(shù)的區(qū)別
指針函數(shù)是返回值是某一類型指針的函數(shù),即本質(zhì)是一個(gè)函數(shù),指針函數(shù)定義:int *fun(int x);,舉個(gè)例子如下
float *fun();
float *p;
p = fun(a);
這個(gè)函數(shù)的返回值是一個(gè)地址值,賦值給用同類型的指針變量p,也就是說,指針函數(shù)一定有函數(shù)返回值,而且在主調(diào)函數(shù)中,函數(shù)返回值必須賦給同類型的指針變量。
兩者主要的區(qū)別是一個(gè)是指針變量,一個(gè)是函數(shù)。
typedef void(*Func)(void)為什么能這么用?
可能我們有這樣的疑問,typedef一般的用法不是取個(gè)新名字嗎?如果仿照變量類型聲明,應(yīng)該是這樣typedef void(*)() variable;才比較眼熟易懂。
說一說我的理解,我們知道C語言的函數(shù)在被調(diào)用的時(shí)候是執(zhí)行了一條轉(zhuǎn)移指令,這條指令包含要轉(zhuǎn)移到的地方的數(shù)據(jù),同理,變量代表了一個(gè)地址,當(dāng)你引用一個(gè)變量的時(shí)候,計(jì)算機(jī)會把這個(gè)地址的數(shù)據(jù)拿出來參與運(yùn)算。
那么函數(shù)名也是一樣,函數(shù)名代表的是一段代碼的入口地址,引用了這個(gè)函數(shù),那么計(jì)算機(jī)會使用轉(zhuǎn)移指令轉(zhuǎn)移到函數(shù)名代表的地址。
所以typedef void(*Func)(void)相當(dāng)于定義了一種類型,這個(gè)類型具有下面的特征:他是一個(gè)函數(shù),沒有返回值,沒有參數(shù)。
因?yàn)樘幚砥髟谶M(jìn)行上下文切換或者轉(zhuǎn)移的時(shí)候要進(jìn)行現(xiàn)場保護(hù),不同的函數(shù)對現(xiàn)場保護(hù)的內(nèi)容可能不一樣,傳入的參數(shù)使用的棧也不一樣,相同類型的函數(shù)保證了現(xiàn)場保護(hù)的內(nèi)容是一樣的,參數(shù)的形式也是一樣的。所以這樣使用可以像用指針引用數(shù)據(jù)一樣使用函數(shù)。
typedef void(*Func)(void)的應(yīng)用
用法的好處,定義一個(gè)函數(shù)指針類型。
例子:
上面說到typedef void(*Func)(void)可以使得代碼更可移植性、可讀性更強(qiáng),我們舉個(gè)例子,有三個(gè)類型相似或功能相似的函數(shù):
//構(gòu)造3個(gè)通用函數(shù)
void TEST1(void) { printf("test1\n"); }//函數(shù)定義
void TEST2(void) { printf("test2\n"); }//函數(shù)定義
void TEST3(void) { printf("test3\n"); }//函數(shù)定義
... ...
//聲明
typdef void (*func)(void);
再來定義一個(gè)調(diào)用的函數(shù)
void test(int i)
{
func vTask[3] = {&TEST1, &TEST2, &TEST3};
func fun = vTask[i];
(*fun)();
}
在main函數(shù)中,分別調(diào)用這幾個(gè)不同輸入?yún)?shù)的函數(shù)
void main()
{
test(0);
test(1);
test(2);
return 0;
}
這樣的話代碼就看著很舒服了。
參考:https://blog.csdn.net/flyztek/article/details/73610255
嵌入式編程專輯 Linux 學(xué)習(xí)專輯 C/C++編程專輯 Qt進(jìn)階學(xué)習(xí)專輯
關(guān)注我的微信公眾號,回復(fù)“加群”按規(guī)則加入技術(shù)交流群。
點(diǎn)擊“閱讀原文”查看更多分享。
