????函數(shù)是C語(yǔ)言的核心概念。主調(diào)函數(shù)(caller)調(diào)用被調(diào)函數(shù)(callee)是一般的調(diào)用關(guān)系,如果被調(diào)函數(shù)(callee)參數(shù)包含函數(shù)指針,函數(shù)指針還可以形成多一層的調(diào)用關(guān)系,形成第三方函數(shù)的調(diào)用,專(zhuān)業(yè)術(shù)語(yǔ)稱(chēng)為回調(diào)(callback),通過(guò)函數(shù)指針參數(shù)調(diào)用的第三方函數(shù)稱(chēng)為回調(diào)函數(shù)。
? ????回調(diào)可以讓被調(diào)函數(shù)(這里是指用函數(shù)指針做函數(shù)參數(shù)的函數(shù))的代碼更加泛化或抽象,能夠簡(jiǎn)單模擬其它編程語(yǔ)言的委托與反射語(yǔ)法。
?
1、簡(jiǎn)單模擬委托
?
//C語(yǔ)言簡(jiǎn)單模擬委托 //需要用的指針函數(shù)。通過(guò)用指針函數(shù)作為地址接收函數(shù)地址,以達(dá)到委托其他函數(shù)實(shí)現(xiàn)某方法的目的。 #includetypedef void(* fun)(); //typedef 把void(*)()類(lèi)型重命名為fun void func(fun); // 被調(diào)函數(shù) void func_1(); // 回調(diào)函數(shù)1 void func_2(); // 回調(diào)函數(shù)2 int main() // 主函數(shù)用做主調(diào)函數(shù) { func(func_1); fun f = func_2; f(); func(func_1); func(func_2); getchar(); return 0; } void func(fun f) //fun f為地址,fun * f為f指向的地址的量或者其他 { printf("func "); if (f != NULL) { f(); } } void func_1() { printf("func_1 "); } void func_2() { printf("func_2 "); } /* func func_1 func_2 func func_1 func func_2 */
?
2、簡(jiǎn)單模擬反射
?
(1)簡(jiǎn)單模擬反射
????高級(jí)語(yǔ)言的反射機(jī)制,簡(jiǎn)單來(lái)說(shuō)就是可以通過(guò)字符串型獲取對(duì)應(yīng)的類(lèi)或者函數(shù)。
?
????下面用C來(lái)簡(jiǎn)單模擬反射:
?
?
#include#include typedef void (*callback)(void); typedef struct { const char *name; callback fn; }callback_t; void f0(); void f1(); callback_t callbacks[] = { {"cmd0", f0}, {"cmd1", f1}, }; void f0() // 回調(diào)函數(shù)0 { printf("cmd0"); } void f1() // 回調(diào)函數(shù)1 { printf("cmd1"); } void do_callback(const char *name) { size_t i; for (i = 0; i < sizeof(callbacks) / sizeof(callbacks[0]); i++) { if (!strcmp(callbacks[i].name, name)) { callbacks[i].fn(); } } } int main() { do_callback("cmd1"); getchar(); return 0; }
?
(2)利用自定義段
????gcc支持通過(guò)使用 __ attribute __ ((section())),將函數(shù)、變量放到指定的數(shù)據(jù)段中。
?
????也就是說(shuō),可以讓編譯器幫我們完成上例中向數(shù)組添加成員的動(dòng)作。借助此機(jī)制,回調(diào)函數(shù)可以在任意文件聲明,不需要修改其他文件。自定義段的起始和結(jié)束地址,可以通過(guò)變量 __ start_SECTIONNAME 和 __ stop_SECTIONNAME得到例如通過(guò) __ attribute __ ((section("ss"))定義自定義段,其開(kāi)始地址為 & __ start_ss,結(jié)束地址為 & __stop_ss。
?
?
// https://www.bejson.com/runcode/c920/ #include#define SEC __attribute__((__section__("ss"), aligned(sizeof(void*)))) void func_1 (int a, int b) { printf("%s %d %d ", __func__, __LINE__, a+b); } void func_2 (int a, int b) { printf("%s %d %d ", __func__, __LINE__, a*b); } // 編譯器會(huì)自動(dòng)提供__start_ss,__stop_ss標(biāo)志段ss的起止地址 extern size_t __start_ss; extern size_t __stop_ss; typedef struct { void (*p)(int, int); } node_t; // 結(jié)構(gòu)體變量a位于自定義段ss SEC node_t a = { .p = func_1, }; SEC node_t b = { .p = func_2, }; int main(int argc, char **argv) { int a = 3, b = 4; node_t *p; // 遍歷段ss,執(zhí)行node_t結(jié)構(gòu)中的p指向的函數(shù) for (p = (node_t *)&__start_ss; p < (node_t *)&__stop_ss;p++) { p->p(a, b); a+=1;b+=2; } } /* func_1 6 7 func_2 10 24 */
?
審核編輯:湯梓紅
?
評(píng)論
查看更多