2013-05-31 13 views
6

Mac OS Xで実行時にライブラリ関数に動的にリンクする必要があります。Apple's exampleに続いて、関数ポインタを宣言し、dlsym()の結果を代入します。次の例では、プレーンなC(.c)ファイルとして正常にコンパイルされます。しかし、私はC++ファイルでこれを必要とする、と私はC++ファイル(.cppファイル)としてこの例をコンパイルする場合は、打ち鳴らすコンパイラは私に語っ機能ポインタの代入はC言語で行われますが、C++では動作しません

は型の変数を初期化できません「無効()(のchar *)」 'void 'の値を持つ

なぜそれはプレーンな 'C'で動作するのですか?これをどのように修正できますか?

#include <dlfcn.h> 

void Test() { 
    // Load the library which defines myFunc 
    void* lib_handle = dlopen("myLib.dylib", RTLD_LOCAL|RTLD_LAZY); 

    // The following line is an error if compiled as C++ 
    void (*myFunc)(char*) = dlsym(lib_handle, "myFunc"); 

    myFunc("Hello"); 

    dlclose(lib_handle) ; 
} 

答えて

7

void*を返します。 POSIXでは(標準Cではなく、Jamesが指摘するように)void*から関数型へのポインタへの暗黙的な変換があるので、myFuncへの代入はちょうど機能します。

void (*myFunc)(char*) = (void(*)(char*))dlsym(lib_handle, "myFunc"); 

(またはあなたがreinterpret_castと空想取得することができます):あなたは本当にキャストを追加することによって、それを意味するコンパイラに指示する必要がありますので、C++では暗黙の変換は、(それが安全で入力していないため)がありません。

+0

...または多分 'static_cast':http://stackoverflow.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to- whatever –

+2

私が持っているC標準のバージョンでは、 'void'へのポインタは' _object_ type'へのポインタに変換される可能性があります。関数はオブジェクト型ではなく、Cは 'void *'と関数へのポインタの間の変換(明示的または暗黙的な)を許さなかった。私は確信が持てませんが、診断が必要だと思います。 (私はそれが未定義の振る舞いだとは思わない)。明示的なキャスト( 'reinterpret_cast'さえ)もうまくいかないはずです。 (ほとんどのUnixコンパイラはこれに準拠していませんが、拡張機能なので各コンパイラは自由に動作します) –

+0

@JamesKanzeが正しいです、Cは 'void *'から 'pointer-to-関数型です。準拠しているCコンパイラは、診断を発行する必要があります(これは単なる警告に過ぎません)。非適合のCコンパイラは、デフォルトでほとんどのものが好きなことをすることができます。 –

0

Cコンパイラが壊れているためです。 と 関数へのポインタの間の変換はありません(明示的または暗黙的).CでもC++でもありません。

void (*myFunc)(char *); 
*(void (**myFunc)(char*))(&myFunc) = dlsym(...); 

が動作する:

POSIXではよう 、Cに制限を追加し、機能にvoid*と ポインタが同じサイズと表現を持つことが必要です。 (もちろん、もう少しエラーチェックで)

class GetFunctionHelper; 
GetFunctionHelper getFunction(void* dlHandle, std::string const& functionName); 

class GetFunctionHelper 
{ 
    void* fromSystem; 
    freind GetFunctionHelper getFunction(void* , std::string const&); 
    GetFunctionHelper(void* fromSystem) : fromSystem(fromSystem) {} 
public: 
    template <typename Ptr> operator Ptr() const 
    { 
     return *reinterpret_cast<Ptr const*>(&fromSystem); 
    } 
}; 

GetFunctionHelper 
getFunction(void* dlHandle, std::string const& functionName) 
{ 
    return GetFunctionHelper(dlsym(dlHandle, functionName.c_str())); 
} 

C++では、次のようなものを使用することをお勧めします。

+0

'void *'から関数型へのポインタへの明示的な変換(つまりキャスト)は、私が知る限り、いかなる制約にも違反しません。しかし、標準ではそのような変換の動作が定義されていないため、その動作は定義されていません。 POSIXはおそらく自由であるので、動作を定義します。 –

+0

ありがとう、@ジェームス。私はコンパイラの不足について十分に言及するほどスマートではない。また、2行目はコンパイルされません。 typo 'u'対 'y'のほかに、明らかに右括弧が欠けていますが、どこに行かなければならないのか分かりません。 –

+0

@KeithThompson私はCについては分かりません。 C++では、診断が必要です。ごく最近まで、Posixは基本的に私の最初の例を使用すると言っていました。しかし、今回私はこれを見て、コンパイラエクステンションを使うと言いました。だから私は知らない(Cに関して)。実際には、私はいつも私のC++バージョンのようなものを使用していたので、この問題は決して起きませんでした(このルールを適用したUnixコンパイラは見たことがありません)。 –

関連する問題