2009-04-09 23 views
2

我有這個程序,我希望其他進程能夠調用函數(通過unix套接字)。消息協議非常簡單,函數名稱,函數簽名和保存參數的緩衝區(char *)。C RPC沒有存根

當我的程序中的某個模塊想要允許某個功能可訪問時,它會在庫中註冊名稱和簽名。我面臨的問題是在請求進來後,物理上調用函數。我已經查看了RPC和Java RMI類庫,但這些需要我生成存根以包裝調用。我正在使用的系統非常有活力,我還必須與其他人無法修改的代碼進行交互。

因此,基本上,一個函數可能看起來像:

//   func ptr name  signature 
REG_FUNCTION(somefunc, "somefunc", "i:id"); 

當請求到來時,我做了一些錯誤檢查,一旦有效我想:

int somefunc(int someparam, double another) 
{ 
    return 1234; 
} 

現在我與圖書館登記調用該函數。所以我有變量:

void * funcptr = (the requested function); 
char * sig = (the function signature); 
char * params = (a buffer of function parameters); 
//note that the params buffer can hold data types of arbitrary lengths 

如何使用C中的參數調用函數?

謝謝!

+0

你需要什麼簽名?客戶端調用函數還是將請求傳遞給包含somefunc的庫?一些澄清將有所幫助! – dirkgently 2009-04-09 06:45:41

回答

2

我不認爲這是完全可以解決的一般情況,只使用C.您不知道目標函數使用的調用約定,例如。你最終會「欺騙」編譯器,或者至少不得不猜測它。如果編譯器決定使用在寄存器中傳遞的參數來構建註冊函數,那麼可能是由於某種優化設置(或者如果它是使用不同的編譯器構建的呢?)。

在C語言中,通常也沒有辦法用一組給定的參數調用一個函數,並且參數的值需要從隨機字節的緩衝區中解壓縮。

你可以做一些可怕的事情是這樣的:

enum { VOID_INT, VOID_INT_DOUBLE, VOID_DOUBLE_INT, ... } Signature; 

void do_call(const void *userfunction, const void *args, Signature sig) 
{ 
    switch(signature) 
    { 
    case VOID_INT: 
    { 
     int x = *(int *) args; 
     void (*f)(int) = userfunction; 
     f(x); 
     break; 
    } 
    case VOID_INT_DOUBLE: 
    ... 
    } 
} 

但它是很清楚,這並不住在同一大洲的可擴展性。當然,您可以自動生成此代碼,以獲得一些合理的返回類型和參數類型。對於從void *轉換函數指針或者從void *轉換函數指針,你仍然會感到冷清,但這可能是可以接受的。儘管如此,您仍然總是冒着有人向您遞交您沒有預先生成代碼的簽名的風險。

0

結帳libffi。該庫允許使用在運行時指定的一組參數來調用函數。