16

我正在尝试使用 g++从Program-Library-HOWTO编译以下简单的 DL 库示例代码。这只是一个示例,因此我可以学习如何使用和编写共享库。我正在开发的库的真实代码将用 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 编译但不使用克++。所以我通过将上面的第 16 行更改为:

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

有了这个,我收到以下错误:

foo.cpp:16: 错误:不能在赋值中将 'double*' 转换为 'double (*)(double)'

这些问题可能更多地与我自己对适当的 C++ 编码标准的普遍无知有关,而不是其他任何事情。谁能给我指出一个关于使用 C++ 示例代码为 Linux 开发动态库的好教程?

4

4 回答 4

27

C 允许隐式转换void *为任何指针类型(包括函数指针);C++ 需要显式转换。正如 leiflundgren 所说,您需要将返回值dlsym()转换为所需的函数指针类型。

许多人发现 C 的函数指针语法很尴尬。一种常见的模式是 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)

所以这是编译器错误是一个很好的线索的罕见情况之一。;)

于 2009-01-27T15:29:56.263 回答
0

以您的代码编写方式,这实际上更像是一个 C 问题,但您可以让它在 C++ 中工作。我没有关于动态共享库的教程(您链接到的网页看起来不错),但这里是如何在 C++ 中修复您的代码:

  • 将 my_cos 声明为将(最终)调用动态加载的余弦函数的函数:

    double my_cos(double);
    
  • 将函数指针分配给 my_cos

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

这有点复杂,但它为 my_cos 分配了返回双精度的东西,是取消引用另一个函数指针的结果,并将双精度作为参数。正如其他人所发布的,C++ 比 C 对代码的明确性要求更高。

  • 用 std::cerr 或 std::cout 替换那个过时的 fputs 消息:

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

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

希望对此有所帮助。如果那些奇怪的东西吓到你,我会推荐 van Linden 的 Deep C Secrets,当然还有 Kernighan 和 Ritchie Book on C。

编辑:关于您如何专门寻找 C++ 而不是 C 中的开发指南以避免此类问题的评论中的要点。我不知道 C++ 中的可比指南,但大约 99% 的 C 代码可以嵌入到 C++ 代码中并且工作得很好。这种函数指针情况是例外之一。

于 2009-01-27T15:39:44.403 回答
0

在 C++ 中,您必须执行reinterpret_cast(不是 C 强制转换):

typedef double (* double_from_double_function_t(double));
…
double_from_double_function_t cosine = reinterpret_cast<double_from_double_function_t>(dlsym(handle, "cos"));
于 2019-02-07T21:07:56.947 回答