Dynamic Shared Library compilation with g++

2019-03-08 12:00发布

I'm trying to compile the following simple DL library example code from Program-Library-HOWTO with g++. This is just an example so I can learn how to use and write shared libraries. The real code for the library I'm developing will be written in 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);
}

If I compile the program with gcc it works fine.

gcc -o foo foo.c -ldl

When I change the filename and compiler to the following

g++ -o foo foo.cpp -ldl

I get the following error:

foo.cpp:16: error: invalid conversion from 'void*' to 'double (*)(double)'

I understand (I think I understand, correct me if this is wrong) that I can't do an implicit cast from a void pointer in C++, but C lets me, and this is why the above code will compile using gcc but not using g++. So I tried an explicit cast by changing line 16 above to:

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

With this in place, I get the following error:

foo.cpp:16: error: cannot convert 'double*' to 'double (*)(double)' in assignment

These problems probably have more to do with my own general ignorance of proper C++ coding standards than anything else. Can anyone point me to a good tutorial on developing dynamic libraries for Linux that uses C++ example code?

4条回答
家丑人穷心不美
2楼-- · 2019-03-08 12:25

C allows implicit casts from void * to any pointer type (including function pointers); C++ requires explicit casting. As leiflundgren says, you need to cast the return value of dlsym() to the function pointer type you need.

Many people find C's function pointer syntax awkward. One common pattern is to typedef the function pointer:

typedef double (*cosine_func_ptr)(double);

You can define your function pointer variable cosine as a member of your type:

cosine_func_ptr cosine;

And cast using the type instead of the awkward function pointer syntax:

cosine = (cosine_func_ptr)dlsym(handle, "cos");
查看更多
forever°为你锁心
3楼-- · 2019-03-08 12:34

In C++, you have to perform a reinterpret_cast (not a C cast):

typedef double (* double_from_double_function_t(double));
…
double_from_double_function_t cosine = reinterpret_cast<double_from_double_function_t>(dlsym(handle, "cos"));
查看更多
戒情不戒烟
4楼-- · 2019-03-08 12:41

With the way your code if written, this is really more of a C question, but you can get this to will work in C++. I don't have a tutorial for you on Dynamic Shared Libraries (the web page you linked to seems fine), but here's how to fix your code in C++:

  • declare my_cos to be a function that will (eventually) call the dynamically loaded cosine function:

    double my_cos(double);
    
  • assign the function pointer to my_cos

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

This is a little complicated, but it's assigning to my_cos something that returns a double, is the result of dereferencing another function pointer, and takes a double as an argument. As other people have posted, C++ is a little more demanding about the explicitness of your code than C.

  • replace that rather dated fputs message with a std::cerr or std::cout:

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

and

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

Hope that this help. If that weird casty stuff scares you, I'd recommend Deep C Secrets by van Linden, and definitely the Kernighan and Ritchie Book on C.

Edit: Good point in the comment about how you're specifically looking for a development guide in C++ rather than C to avoid this type of problem. I don't know of a comparable guide in C++, but about 99% of C code can be embedded in C++ code and work just fine. This function pointer case is one of the exceptions.

查看更多
The star\"
5楼-- · 2019-03-08 12:43

dlsym returns a pointer to the symbol. (As void* to be generic.) In your case you should cast it to a function-pointer.

 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)

So this one of these rare cases where the compiler error is a good clue. ;)

查看更多
登录 后发表回答