【问题标题】:Dynamic Shared Library compilation with g++使用 g++ 编译动态共享库
【发布时间】:2010-10-03 18:49:33
【问题描述】:

我正在尝试使用 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 但不使用 g++ 编译。所以我通过将上面的第 16 行更改为:

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

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

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

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

【问题讨论】:

  • 我建议通过“用 C++ 思考”来了解 C++。正如您正确发现的那样,您不能从 void* 隐式转换为 C++ 中的其他指针,这意味着您真的只需要了解 C++ 而不是其他领域 :)
  • 谢谢,我在业余时间阅读 C++ Primer,但现在我有一个项目到期。

标签: c++ linux g++ shared-libraries


【解决方案1】:

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");

【讨论】:

  • 我不禁想到你必须读懂我的想法才能弄清楚我真正的问题是什么。谢谢你。 :)
  • 使用 reinterpret_cast() 而不是 C cast 运算符。
【解决方案2】:

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)

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

【讨论】:

  • 这适用于 double (*cosine)(double);来自原始代码,但不是您提供的函数指针声明。由于我是在这里提出问题的无知者,因此我认为我不应该更改您的代码。 :)
【解决方案3】:

按照您的代码编写方式,这实际上更像是一个 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 的 C 书。

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

【讨论】:

  • 提供的示例代码是C,但我将使用C++开发,所以我需要用g++编译。这个问题可能很幼稚,答案可能是“不要用 g++ 编译 C 代码”。 :)
【解决方案4】:

在 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"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    相关资源
    最近更新 更多