假設我們需要提供一個 so 給其他人用,并這個 so 需要執(zhí)行初始化動作,你會怎么來設計?
方法1:簡單粗暴
這種方法應該是最容易想到到的,直接簡單粗暴,提供接口,讓調(diào)用者來處理,示例如下:
/****** method1.c ******/
void method1_init(void)
{
printf("calling method1_init...\r\n");
}
void method1_dosomething(void)
{
printf("calling method1_dosomething...\r\n");
}
/****** main.c ******/
extern void method1_init(void);
extern void method1_dosomething(void);
int main(int argc, char *argv[])
{
printf("test main run...\r\n");
method1_init();
method1_dosomething();
return 0x00;
}
方法2:安能辨我是雌雄
直接上碼再說吧。
/***** method2.c *****/
void __method2_init(void);
void __method2_dosomething(void);
static void (*fun)(void) = __method2_init;
void __method2_init(void)
{
printf("calling method2_init...\r\n");
fun = __method2_dosomething;
fun();
}
void __method2_dosomething(void)
{
printf("calling method2_dosomething...\r\n");
}
void method2_dosomething(void)
{
fun();
}
/****** main.c ******/
extern void method2_dosomething(void);
int main(int argc, char *argv[])
{
printf("test main run...\r\n");
method2_dosomething();
return 0x00;
}
這里的 method2_dosomething 接口既是提供服務的接口也是初始化的接口。
只會在第一次調(diào)用它的時候執(zhí)行 init 動作,這里利用了函數(shù)指針,對調(diào)用者來說非常的友好。
嚴格來做這里的靜態(tài)函數(shù)指針變量相當于引入了狀態(tài),在多線程調(diào)用過程中需要加鎖。
方法3:GCC 的黑魔法
這里用到了 gcc 的一個設置函數(shù)屬性的功能,讓其在加載過程自動的被調(diào)用,如下:
/***** method3.c *****/
__attribute__((constructor)) void __method3_init(void)
{
printf("calling method3_init...\r\n");
}
void method3_dosomething(void)
{
printf("calling method3_dosomething...\r\n");
}
/****** main.c ******/
extern void method3_dosomething(void);
int main(int argc, char *argv[])
{
printf("test main run...\r\n");
method3_dosomething();
return 0x00;
}
被 <code>__attribute__((constructor))</code> 修飾的函數(shù)會先于 main 函數(shù)執(zhí)行,同時會自動的被調(diào)用。
這種方法得益于編譯器的支持,對于調(diào)用者來說也是非常友好,同時不需要像方法2一樣在多線程使用中需要用到鎖的機制,此種方法實現(xiàn)更簡單。
好了,這里主要介紹三種怎么處理一個模塊初始化的方法,三種各有優(yōu)缺點吧,適合才是最好的,項目中選擇最適合自己實際情況的方法就好。
如果你有更好的方法或想法,歡迎評論留言,謝謝!
掃碼關(guān)注我了解更多
