函數(shù)是C語言的核心概念。主調(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)用,專業(yè)術(shù)語稱為回調(diào)(callback),通過函數(shù)指針參數(shù)調(diào)用的第三方函數(shù)稱為回調(diào)函數(shù)?;卣{(diào)可以讓被調(diào)函數(shù)(這里是指用函數(shù)指針做函數(shù)參數(shù)的函數(shù))的代碼更加泛化或抽象,能夠簡單模擬其它編程語言的委托與反射語法。 1 簡單模擬委托//C語言簡單模擬委托//需要用的指針函數(shù)。通過用指針函數(shù)作為地址接收函數(shù)地址,以達到委托其他函數(shù)實現(xiàn)某方法的目的。#include <stdio.h>typedef void(* fun)(); //typedef 把void(*)()類型重命名為funvoid func(fun); // 被調(diào)函數(shù)void func_1(); // 回調(diào)函數(shù)1void func_2(); // 回調(diào)函數(shù)2int 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\n'); if (f != NULL) { f(); }}void func_1(){ printf('func_1\n');}void func_2(){ printf('func_2\n');}/*funcfunc_1func_2funcfunc_1funcfunc_2*/
2 簡單模擬反射 //C語言簡單模擬反射//高級語言的反射機制,簡單來說就是可以通過字符串型獲取對應的類或者函數(shù)。#if 0#include <stdio.h>#include <string.h>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;}#else/*上例的不便之處在于,當需要映射的函數(shù)因分散在不同文件時,每增加一個新的映射都需要修改這個數(shù)組,以及頭文件。2 利用自定義段gcc支持通過使用__attribute__((section())),將函數(shù)、變量放到指定的數(shù)據(jù)段中。也就是說,可以讓編譯器幫我們完成上例中向數(shù)組添加成員的動作。借助此機制,回調(diào)函數(shù)可以在任意文件聲明,不需要修改其他文件。自定義段的起始和結(jié)束地址,可以通過變量__start_SECTIONNAME和__stop_SECTIONNAME得到例如通過__attribute__((section('ss'))定義自定義段,其開始地址為&__start_ss,結(jié)束地址為&__stop_ss*/// https://www./runcode/c920/#include <stdio.h>#define SEC __attribute__((__section__('ss'), aligned(sizeof(void*))))void func_1 (int a, int b){ printf('%s %d %d\n', __func__, __LINE__, a+b); }void func_2 (int a, int b){ printf('%s %d %d\n', __func__, __LINE__, a*b); }// 編譯器會自動提供__start_ss,__stop_ss標志段ss的起止地址extern size_t __start_ss;extern size_t __stop_ss;typedef struct { void (*p)(int, int);} node_t;// 結(jié)構(gòu)體變量a位于自定義段ssSEC 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 7func_2 10 24*/#endif
-End-
|