代码之家  ›  专栏  ›  技术社区  ›  Bill the Lizard

使用g进行动态共享库编译++

  •  17
  • Bill the Lizard  · 技术社区  · 17 年前

    我正试图从编译以下简单的DL库示例代码 Program-Library-HOWTO 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)”的转换无效

    我明白(I 认为 我明白,如果这是错误的,请纠正我)我不能在C++中从空指针进行隐式转换,但C允许我这样做,这就是为什么上面的代码将使用gcc而不是g++编译的原因。因此,我尝试将上面的第16行更改为:

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

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

    foo.cpp:16:错误:无法在赋值中将“double*”转换为“double(*)(double)”

    这些问题可能更多地与我自己对正确的C++编码标准的普遍无知有关。有人能给我推荐一个使用C++示例代码为Linux开发动态库的好教程吗?

    4 回复  |  直到 17 年前
        1
  •  25
  •   Commodore Jaeger    17 年前

    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");
    
        2
  •  9
  •   Vadim Kotov First Zero    8 年前

    dlsym 返回指向该符号的指针。(As 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)
    

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

        3
  •  0
  •   Vadim Kotov First Zero    8 年前

    按照你的代码编写方式,这实际上更像是一个C问题,但你可以用C++来解决这个问题。我没有动态共享库的教程(你链接到的网页似乎很好),但以下是如何在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;
    

    希望这能有所帮助。如果你害怕这些奇怪的东西,我会推荐范·林登的《Deep C Secrets》,当然还有《Kernighan and Ritchie关于C的书》。

    编辑:评论中有一个很好的观点,即你如何专门寻找C++而不是C的开发指南来避免这类问题。我不知道C++中有没有类似的指南,但大约99%的C代码可以嵌入C++代码中,并且工作得很好。此函数指针大小写是例外之一。

        4
  •  0
  •   Xavier Lamorlette    7 年前

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