2012-04-29 99 views
1

我有以下代碼,它只從當前目錄加載庫test.so,並在該庫中執行version函數。應該返回的是一個字符串。反而返回的是堆棧中的垃圾(指針位置可能?)。有誰知道爲什麼下面的代碼會失敗。動態庫函數調用

#include <stdio.h> 
#include <stdlib.h> 
#include <dlfcn.h> 

int main(int argc, char **argv){ 
    void *handler; 
    char *(*version); 
    char *error; 

    handler = dlopen("./test.so", RTLD_LAZY); 
    if(!handler){ 
     fprintf(stderr, "%s\n", dlerror()); 
     exit(EXIT_FAILURE); 
    } 

    dlerror(); //Flushes any existing error 

    *(void **)(&version) = dlsym(handler, "version"); 

    if((error = dlerror()) != NULL){ 
     fprintf(stderr, "%s\n", error); 
     exit(EXIT_FAILURE); 
    } 
    printf("%s\n", version); 
    dlclose(handler); 
    exit(EXIT_SUCCESS); 
} 

回答

4

更改聲明:

char *(*version); // this is not a function pointer 

到:

char *(*version)(); // but this is 

然後,更改行:

printf("%s\n", version); 

到:

printf("%s\n", version()); 
3

dlsym只是返回一個函數指針。您仍然需要實際調用它,您可以通過將(void *)強制轉換爲適當類型的函數指針並調用它來完成。

+0

將'version'轉換爲'(char *)版本'仍然返回垃圾。 – Blackninja543

2

有兩個錯誤在你的代碼:

version聲明:這是一個指針的指針在你的代碼爲char,這導致你一個奇怪的轉換中:

*(void **)(&version) = dlsym(handler, "version"); 

而是使用函數指針返回字符指針,像這樣:

char *(*version)(); 

,並使用常規分配:

version = dlsym(handler, "version"); 

打印結果時,您沒有調用該函數。在C中,只寫入函數名稱將返回其地址,因此version&version是等效的。你的代碼應該是這樣的:

printf("%s\n", version()); 
+0

實際使用的醜陋的別名違反規則的指針轉換OP來自POSIX文檔。 :-(然而,它不應該被使用,沒有強制轉換的版本也會被破壞,然而'void *'不會轉換爲函數指針類型,唯一正確的解決方案是:'char *(* version)(); void * tmp = dlsym(處理程序,「版本」); memcpy(&版本,&tmp,sizeof版本);' –

+0

感謝你我實際閱讀手冊;)。儘管現在我沒有看到POSIX示例的問題。 –

+0

問題出在這裏的例子:http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html理由解釋了他們爲什麼寫他們沒有寫明顯的方式示例(ISO C要求編譯器來生成數據指針到函數指針的轉換診斷),但未能解決這樣的事實,即它們通過訪問錯誤類型的對象來違反別名規則(因此編譯器可以優化它或打破通過重新排序讀/寫代碼)。如果你想壓制警告,'memcpy'版本是我知道編寫它的唯一安全方式。 –