16

Program-Library-HOWTOの次の簡単な DL ライブラリのサンプル コードを g++ でコンパイルしようとしています。これは単なる例であるため、共有ライブラリの使用方法と作成方法を学ぶことができます。私が開発しているライブラリの実際のコードは、C++ で記述されます。

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

int main(int argc, char **argv) {
    void *handle;
    double (*cosine)(double);
    char *error;

    handle = dlopen ("/lib/libm.so.6", RTLD_LAZY);
    if (!handle) {
        fputs (dlerror(), stderr);
        exit(1);
    }

    cosine = dlsym(handle, "cos");
    if ((error = dlerror()) != NULL)  {
        fputs(error, stderr);
        exit(1);
    }

    printf ("%f\n", (*cosine)(2.0));
    dlclose(handle);
}

プログラムを gcc でコンパイルすると、正常に動作します。

gcc -o foo foo.c -ldl

ファイル名とコンパイラを次のように変更すると

g++ -o foo foo.cpp -ldl

次のエラーが表示されます。

foo.cpp:16: エラー: 'void*' から 'double (*)(double)' への変換が無効です

C ++ではvoidポインターから暗黙のキャストを実行できないことを理解しています(理解したと思います、これが間違っている場合は修正してください)が、Cでは許可されています。これが、上記のコードがgccを使用してコンパイルするが、使用しない理由ですg++. そこで、上記の 16 行目を次のように変更して、明示的なキャストを試みました。

cosine = (double *)dlsym(handle, "cos");

これを行うと、次のエラーが表示されます。

foo.cpp:16: エラー: 代入で 'double*' を 'double (*)(double)' に変換できません

これらの問題は、他の何よりも、適切な C++ コーディング標準に対する私自身の一般的な無知に関係している可能性があります。C++ のサンプル コードを使用する Linux 用の動的ライブラリの開発に関する優れたチュートリアルを教えてくれる人はいますか?

4

4 に答える 4

27

void *C では、任意のポインター型 (関数ポインターを含む) への暗黙的なキャストが可能です。C++ では、明示的なキャストが必要です。leiflundgren が言うように、戻り値をdlsym()必要な関数ポインター型にキャストする必要があります。

多くの人は、C の関数ポインターの構文が扱いにくいと感じています。一般的なパターンの 1 つは、関数ポインターを typedef することです。

typedef double (*cosine_func_ptr)(double);

関数ポインター変数cosineを型のメンバーとして定義できます。

cosine_func_ptr cosine;

そして、ぎこちない関数ポインター構文の代わりに型を使用してキャストします。

cosine = (cosine_func_ptr)dlsym(handle, "cos");
于 2009-01-27T15:38:04.673 に答える
9

dlsymシンボルへのポインタを返します。(void*一般的であるように。)あなたの場合、それを関数ポインタにキャストする必要があります。

 double (*mycosine)(double); // declare function pointer
 mycosine = (double (*)(double)) dlsym(handle, "cos"); // cast to function pointer and assign

 double one = mycosine(0.0); // cos(0)

したがって、これは、コンパイラ エラーが良い手がかりとなるまれなケースの 1 つです。;)

于 2009-01-27T15:29:56.263 に答える
0

あなたのコードが書かれている場合、これは実際にはCの質問ですが、これをC ++で動作させることができます。動的共有ライブラリに関するチュートリアルはありませんが (リンク先の Web ページは問題ないようです)、C++ でコードを修正する方法は次のとおりです。

  • my_cos を、動的にロードされたコサイン関数を (最終的に) 呼び出す関数として宣言します。

    double my_cos(double);
    
  • 関数ポインタを my_cos に割り当てます

    my_cos = (double (*)(double)) dlsym(handle, "cos");
    

これは少し複雑ですが、my_cos に double を返す何かを割り当てています。これは、別の関数ポインターを逆参照した結果であり、引数として double を取ります。他の人が投稿したように、C++ は C よりもコードの明示性について少し厳しいです。

  • そのかなり古い fputs メッセージを std::cerr または std::cout に置き換えます。

    std::cerr << "error loading library cos: " << error << std::endl;
    

std::cout << "result is " << (*my_cos)(2.0)) << std::endl;

これが役立つことを願っています。その奇妙なカスティーなものがあなたを怖がらせるなら、van LindenによるDeep C Secrets、そして間違いなくCに関するKernighan and Ritchie Bookをお勧めします.

編集: この種の問題を回避するために、C ではなく C++ で開発ガイドを具体的にどのように探しているかについてのコメントの良い点。C++ での同等のガイドは知りませんが、C コードの約 99% は C++ コードに埋め込むことができ、問題なく動作します。この関数ポインターのケースは例外の 1 つです。

于 2009-01-27T15:39:44.403 に答える