外掛程式問題回答第1題

2021-08-30 05:51:41 字數 4422 閱讀 4473

問題貼:[url]

[quote]1. 現有乙個主程式用c語言寫成。現在要允許第三方開發人員編寫擴充套件的模組,約定第三方開發的模組必須提供一系列已知名稱的函式(如 foo(),bar(),baz())。如果要求第三方的模組必須與主程式的二進位制**分開發布,把dll或so丟在某個資料夾內即可被動態裝載並使用,應如何實現?

[/quote]

回答:作業系統提供了shared object的動態裝載功能。定義在dlfcn.h中。呼叫dlopen()開啟外掛程式,dlsym()獲取函式,dlclose()關閉外掛程式。

適用於:

*nix。在linux中實驗成功。

實現:我們假定每個外掛程式提供兩個函式:

void hello(void);  // 顯示hello world

void greet(char* name); // 給你打招呼

為了簡化裝載,我們用乙個struct儲存以上兩個函式的指標,並要求每個外掛程式內提供乙個叫init_module的函式,填充該struct。

介面標頭檔案如下:

/* plugin-inte***ce.h */

#ifndef _plugin_inte***ce_h_

#define _plugin_inte***ce_h_

#ifdef __cplusplus

extern "c" plugininte***ce;

typedef void (*initmodulefunc)(plugininte***ce* iface); // 這個函式填充上述結構。

#ifdef __cplusplus

}#endif

#endif

/* end of plugin-inte***ce.h */

總體的目錄結構如下:

[quote].

|-- makefile

|-- main

|-- main.c

|-- plugin-inte***ce.h

`-- plugins

|-- makefile

|-- goodbyeworld.c

|-- goodbyeworld.o

|-- goodbyeworld.so

|-- helloworld.c

|-- helloworld.o

`-- helloworld.so[/quote]

plugins裡的.so將被主程式main裝載。

看看plugins/helloworld.c:

/* plugins/helloworld.c */

#include

#include "../plugin-inte***ce.h"

// 兩個功能函式hello, greet的名稱隨便。我們只關心它們的指標。

void hw_hello()

void hw_greet(char* name)

// 填充plugininte***ce結構。

void init_module(plugininte***ce *iface)

/* end of plugins/helloworld.c */

plugins/goodbyeworld.c是另乙個外掛程式

/* plugins/goodbyeworld.c */

#include

#include "../plugin-inte***ce.h"

void gw_hello()

void gw_greet(char* name)

void init_module(plugininte***ce *iface)

/* end of plugins/goodbyeworld.c */

最後,main.c是主程式。

/* main.c */

#include

#include

#include

#include // dlopen(), dlsym(), dlclose()

#include

#include

#include "plugin-inte***ce.h"

#define max_plugins 10

char plugins_path = "plugins";

struct plugins[max_plugins]; // 每個struct對應乙個外掛程式

int n_plugins;

void load_plugin(char* path)

init_func = dlsym(lib_handle, "init_module"); // 找到init_module函式。

err = dlerror();

if(err != null)

strcpy(plugins[n_plugins].path,path);

plugins[n_plugins].lib_handle=lib_handle;

init_func(&plugins[n_plugins].iface); // 利用外掛程式中的"init_module"函式,填充iface結構

n_plugins++;

fprintf(stderr,"plugin successfully loaded: %s\n",path);

}int main()

while((dent=readdir(dir))!=null)

closedir(dir);

// 測試每個外掛程式

for(i=0;i// 解除安裝

for(i=0;ireturn 0;

}/* end of main.c */

編譯:

# makefile

all: main

main: main.c plugin-inte***ce.h

gcc -rdynamic -ldl -o $@ $^

# end of makefile

main.c的dlopen()等函式需要-ldl選項。-rdynamic選項也是dlopen()等函式需要的。

# plugins/makefile

all: helloworld.so goodbyeworld.so

helloworld.so: helloworld.c

gcc -c -fpic helloworld.c

gcc -shared -o helloworld.so helloworld.o

goodbyeworld.so: goodbyeworld.c

gcc -c -fpic goodbyeworld.c

gcc -shared -o goodbyeworld.so goodbyeworld.o

# end of plugins/makefile

這些是外掛程式的編譯方法。-fpic是構造so的必要條件。

另乙個選項是-wl,-soname,******x.so.x,這對動態鏈結(靜態裝載)有用,但是不加這個選項仍然可以動態裝載。

執行時,需要的最少的目錄結構如下:

[quote].

|-- main

`-- plugins

|-- goodbyeworld.so

`-- helloworld.so

[/quote]

執行:[quote][wks@localhost out]$ ./main

plugin successfully loaded: plugins/goodbyeworld.so

plugin successfully loaded: plugins/helloworld.so

testing plugins/goodbyeworld.so ...

goodbye world!

goodbye, wks

testing plugins/helloworld.so ...

hello world!

hello, wks

[/quote]

總結:1. main程式並不了解plugins目錄中有多少外掛程式。在執行時列舉目錄。

2. main程式對每個plugins檔案(比如叫helloworld.so)的了解只有:

- helloworld.so中有乙個函式叫init_module,可以填充plugininte***ce結構。

- helloworld.so將實現hello和greet兩個函式,但函式名可以不知道。函式指標被init_module提供。

- 用plugininte***ce結構中的函式操作外掛程式。

參考:

面試常見問題回答技巧(70題)

面試過程中我們往往會遇到很多的提問,有時候容易卡殼,這裡基本涵蓋了絕大部分面試可能出現的提問,主要是講針對提問我們應該從哪些方面去回答,給新人或者初入職場的童鞋一點參考指導 1 請你自我介紹一下你自己,2 你覺得你個性上最大的優點是什麼?3 說說你最大的缺點?4 你對加班的看法?5 你對薪資的要求?...

實驗二(第1題)

標頭檔案 ifndef seqlist h define seqlist h const int maxsize 100 class seqlist seqlist int a,int n seqlist int get int i int locate int x void insert int ...

劍指Offer 第1題

問題 在乙個二維陣列中 每個一維陣列的長度相同 每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成乙個函式,輸入這樣的乙個二維陣列和乙個整數,判斷陣列中是否含有該整數。暴力法 分析 直接遍歷一遍陣列,即可判斷目標target是否存在。複雜度分析 時間複雜度 o n 2 因...