2009-01-27 40 views
11

Tôi đang cố gắng biên dịch mã ví dụ thư viện DL đơn giản sau đây từ Program-Library-HOWTO bằng g ++. Đây chỉ là một ví dụ để tôi có thể học cách sử dụng và viết các thư viện chia sẻ. Mã thực sự cho thư viện mà tôi đang phát triển sẽ được viết bằng C++.Biên dịch Thư viện Chia sẻ Động với g ++

#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); 
} 

Nếu tôi biên dịch chương trình bằng gcc thì nó hoạt động tốt.

gcc -o foo foo.c -ldl 

Khi tôi thay đổi tên tập tin và trình biên dịch như sau

g++ -o foo foo.cpp -ldl 

tôi nhận được lỗi sau:

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

Tôi hiểu (I nghĩ tôi hiểu, chính xác cho tôi nếu điều này là sai) mà tôi không thể làm một diễn viên tiềm ẩn từ một con trỏ void trong C + +, nhưng C cho phép tôi, và đây là lý do tại sao các mã trên sẽ biên dịch bằng cách sử dụng gcc nhưng không usin g g ++. Vì vậy, tôi đã cố gắng chuyển kiểu tường minh bằng cách thay đổi dòng 16 trên để:

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

Với điều này tại chỗ, tôi nhận được thông báo lỗi sau:

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

Những vấn đề này có thể có nhiều việc phải làm với sự thiếu hiểu biết chung của riêng tôi của các tiêu chuẩn mã hóa C++ phù hợp hơn bất kỳ thứ gì khác. Bất cứ ai có thể chỉ cho tôi một hướng dẫn tốt về phát triển thư viện động cho Linux có sử dụng mã ví dụ C++?

+0

Tôi khuyên bạn nên thực hiện 'Suy nghĩ trong C++' để tăng tốc độ trên C++. Khi bạn phát hiện chính xác, bạn không thể ẩn hoàn toàn từ void * sang các con trỏ khác trong C++, và điều đó ngụ ý bạn thực sự chỉ cần tăng tốc trên C++ thay vì các vùng khác :) – workmad3

+0

Cảm ơn, tôi đang đọc C++ Primer trong thời gian rảnh rỗi của tôi, nhưng ngay bây giờ tôi có một dự án do. –

Trả lời

24

C cho phép phôi ẩn từ void * đến bất kỳ loại con trỏ nào (bao gồm con trỏ hàm); C++ yêu cầu truyền rõ ràng. Như leiflundgren nói, bạn cần truyền giá trị trả về của dlsym() đến kiểu con trỏ hàm bạn cần.

Nhiều người thấy cú pháp con trỏ hàm của C khó xử. Một mô hình phổ biến là typedef con trỏ hàm:

typedef double (*cosine_func_ptr)(double); 

Bạn có thể xác định chức năng của bạn trỏ biến cosine như một thành viên của loại hình của bạn:

cosine_func_ptr cosine; 

và Cast sử dụng loại thay vì con trỏ chức năng lúng túng cú pháp:

cosine = (cosine_func_ptr)dlsym(handle, "cos"); 
+0

Tôi không thể không nghĩ rằng bạn phải đọc suy nghĩ của tôi để tìm ra vấn đề thực sự của tôi là gì. Cảm ơn bạn. :) –

+5

Sử dụng reinterpret_cast () thay vì toán tử truyền C. –

9

dlsym trả về con trỏ cho biểu tượng. (Như void* để được chung chung.) Trong trường hợp của bạn, bạn nên đúc nó vào một con trỏ hàm.

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) 

Vì vậy, đây là một trong những trường hợp hiếm hoi mà lỗi trình biên dịch là đầu mối tốt. ;)

+0

Khai báo con trỏ hàm của bạn không. – Arkadiy

+0

Điều này làm việc với đôi (* cosine) (gấp đôi); từ mã gốc, nhưng không phải với khai báo con trỏ hàm bạn đã cung cấp. Vì tôi là người ngu dốt đặt câu hỏi ở đây, tôi không cảm thấy rằng tôi nên thay đổi mã của bạn. :) –

0

Với cách mã của bạn nếu được viết, đây thực sự là một câu hỏi C, nhưng bạn có thể làm điều này để làm việc trong C++.Tôi không có một hướng dẫn cho bạn trên động Shared Libraries (các trang web bạn liên kết đến có vẻ tốt đẹp), nhưng đây là cách khắc phục mã của bạn trong C++:

  • tuyên bố my_cos là một chức năng mà sẽ (cuối cùng) gọi hàm cosin nạp tự động:

    double my_cos(double); 
    
  • gán con trỏ hàm để my_cos

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

Đây là một chút phức tạp, nhưng nó gán cho my_cos một cái gì đó mà trả về một đôi, là kết quả của dereferencing một con trỏ hàm khác, và nhận gấp đôi làm đối số. Như những người khác đã được đăng, C++ là một chút đòi hỏi khắt khe hơn về minh bạch mã của bạn hơn C.

  • thay thế mà fputs nhắn chứ không phải ngày với một std :: cerr hoặc std :: cout:

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

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

Hy vọng rằng sẽ giúp đỡ này. Nếu những thứ kỳ quái đó khiến bạn sợ hãi, tôi muốn giới thiệu Deep C Secrets bởi van Linden, và chắc chắn cuốn sách Kernighan và Ritchie trên C.

Edit: Điểm tốt trong nhận xét về cách bạn đang tìm kiếm một sự phát triển cụ thể hướng dẫn trong C++ thay vì C để tránh loại vấn đề này. Tôi không biết một hướng dẫn có thể so sánh trong C++, nhưng khoảng 99% mã C có thể được nhúng trong mã C++ và hoạt động tốt. Trường hợp con trỏ hàm này là một trong các ngoại lệ.

+0

Mã ví dụ được cung cấp là C, nhưng tôi sẽ phát triển trong C++, vì vậy tôi cần biên dịch với g ++. Câu hỏi có thể ngây thơ và câu trả lời có thể là "Không biên dịch mã C bằng g ++". :) –

Các vấn đề liên quan