2012-03-27 32 views
7

Đây là câu hỏi về định nghĩa hàm C/C++. Mã được thảo luận là các thư viện tĩnhlibRmath cung cấp các định nghĩa trong tệp tiêu đề Rmath.h trong R.Nhiều định nghĩa của hàm trong mã C/C++

documentation được cung cấp cho thư viện nói rằng tùy chọn để người dùng cung cấp định nghĩa hàm cho hàm double unif_rand(void). Vì vậy, câu hỏi của tôi là nếu như một định nghĩa chức năng là tùy chọn, sẽ không có một vấn đề của nhiều định nghĩa chức năng mà không được phép trong C/C++? Không.

Chỉnh sửa: Có thể bạn muốn suy đoán về cách mọi thứ hoạt động mà không cần xem mã nguồn, nhưng đó không phải là điều tôi muốn. Tôi quan tâm để biết làm thế nào nó thực sự hoạt động, vì vậy bạn có thể cần đọc source codedocumentations để trả lời câu hỏi này.

+0

Dự đoán của tôi là chức năng def nằm trong #ifdef để nếu bạn định nghĩa nó, thì máy của bạn được tìm thấy bởi trình liên kết đầu tiên, vì vậy cái đã có ở đó sẽ bị bỏ qua. – baash05

Trả lời

15

Khi bạn đăng ký được liên kết, các biểu tượng chưa được giải quyết sẽ được giải quyết bằng cách sử dụng thư viện bạn cung cấp. Nếu bạn không định nghĩa một hàm, nó sẽ là một biểu tượng chưa được giải quyết trong quá trình liên kết, do đó, liên kết sẽ cố gắng giải quyết biểu tượng đó bằng cách sử dụng librmath, trong trường hợp này. Nếu không thể giải quyết một hoặc nhiều biểu tượng, bạn sẽ gặp lỗi liên kết.

Tuy nhiên, nếu bạn xác định hàm trong mã của mình, nó sẽ được xác định trong quá trình liên kết, vì vậy sẽ không cần phải giải quyết nó bằng các biểu tượng từ thư viện bên ngoài.

Điều bạn không thể làm là xác định cùng một biểu tượng nhiều lần trong ứng dụng của bạn.

Chỉnh sửa: Vì có rất nhiều cuộc tranh luận trong một câu trả lời khác, tôi đã thực hiện một ví dụ thực tế. Tôi đã tạo một đối tượng chia sẻ (tương tự như một DLL trong cửa sổ), trong đó xác định và xuất khẩu một hàm foo:

//lib.h 
extern "C" { 
    void foo(); 
    void bar(); 
}; 

//lib.cpp 
#include <iostream> 
#include "lib.h" 

void foo() { 
    std::cout << "From lib\n"; 
} 

void bar() { 
    std::cout << "Bar, calling foo\n"; 
    foo(); 
} 

Để kiểm tra đối tượng chia sẻ này, tôi đã tạo một ứng dụng được liên kết với nó :

//test.cpp 
#include <iostream> 
#include "lib.h" 

void foo() { 
    std::cout << "From app\n"; 
} 

int main() { 
    bar(); 
} 

tôi đã biên soạn cả hai, các đối tượng chia sẻ và ứng dụng:

g++ lib.cpp -o libtest.so -Wall -fPIC -shared -Wl,--export-dynamic -Wl,-soname,libtest.so -Wl,-z,defs 
g++ test.cpp -o test -L. -ltest 

và khi tôi thực hiện test, thiết lập các đường dẫn thư viện để 01.239., vì vậy đối tượng chia sẻ của tôi có thể được nạp, tôi nhận được kết quả này:

[email protected]:/tmp$ LD_LIBRARY_PATH="." ./test 
Bar, calling foo 
From app 

Như bạn có thể thấy, foo chức năng được xác định trong ứng dụng (không phải là đối tượng chia sẻ) được gọi. Bạn về cơ bản có thể làm điều này cho mỗi biểu tượng xuất khẩu trong một đối tượng được chia sẻ.

EDIT2: tôi đã thêm một hàm được xuất khác trong lib.h. Ứng dụng bây giờ gọi hàm này, kết thúc bằng cách gọi hàm foo. Kết quả là như nhau, như mong đợi.

EDIT3: Ok, chúng ta hãy đi sâu hơn.Đây là bãi từ chức năng bar:

Dump of assembler code for function [email protected]: 
    0x0804855c <+0>: jmp DWORD PTR ds:0x804a004 
    0x08048562 <+6>: push 0x8 
    0x08048567 <+11>: jmp 0x804853c 

Nếu chúng tôi đi đến quyết 0x804a004:

Dump of assembler code for function _GLOBAL_OFFSET_TABLE_: 
    0x08049ff4 <+0>: or  BYTE PTR [edi+0x804],bl 
    0x08049ffa <+6>: add BYTE PTR [eax],al 
    0x08049ffc <+8>: add BYTE PTR [eax],al 
    0x08049ffe <+10>: add BYTE PTR [eax],al 
    ..... 

Như bạn thấy, nó nhảy đến Bảng Global Offset. Bạn có thể đọc về GOT herehere. Ký hiệu động (được giải quyết trong thời gian chạy) được lưu trữ trong bảng này. Bất cứ khi nào bạn gọi một biểu tượng cần được giải quyết khi chạy, bạn thực sự chuyển sang bảng này, và sau đó chuyển đến địa chỉ được lưu trữ trong mục tương ứng của bảng này. Kể từ khi ứng dụng xác định foo, GOT chứa địa chỉ của định nghĩa từ test.cpp, không phải là một trong đối tượng được chia sẻ của chúng tôi.

EDIT4: OK, chỉnh sửa cuối cùng. Trích dẫn từ tài liệu:

Bạn sẽ cần phải cung cấp đồng phục bộ tạo số ngẫu nhiên

double unif_rand(void) 

hoặc sử dụng một trong những cung cấp (và với một thư viện động hoặc DLL bạn sẽ phải sử dụng một trong những cung cấp (...)

Tài liệu rõ ràng nói rằng bạn không thể cung cấp cho mình việc triển khai unif_rand nếu bạn đang sử dụng thư viện động. Do đó, tôi tin rằng những gì tôi đã chỉ ra, thực sự là ans đặt câu hỏi của bạn.

+0

Điều này chủ yếu là nói cùng một điều như tôi đã nói. – Nawaz

+0

Đoạn cuối cùng về cơ bản giống nhau. Phần còn lại thì không. – mfontanini

+0

Chính xác như thế nào? Phần còn lại chỉ là chi tiết. – Nawaz

0

Liên kết thư viện tĩnh hơi khác với việc liên kết tất cả các đối tượng bên trong thư viện tĩnh.

Định nghĩa trong thư viện tĩnh được kéo chỉ khi cần thiết, vì vậy chúng không thể gây ra nhiều lỗi định nghĩa.

Điều này có một số tác dụng phụ, ví dụ: thewell-knownproblem bộ khởi tạo chung bên trong thư viện tĩnh không chạy khi không có gì trong chương trình chính tham chiếu đối tượng đó.

+0

Một bình luận nhỏ; nó có thể đáng giải thích "ví dụ vấn đề nổi tiếng của bộ khởi tạo toàn cục bên trong một thư viện tĩnh không chạy khi không có gì trong chương trình chính tham chiếu đối tượng đó" bởi vì điều đó không có vẻ giống như một vấn đề nhưng âm thanh chính xác; "đối tượng không được sử dụng, do đó, không có chi phí của initialisation" âm thanh tốt hơn so với "mặc dù đối tượng không được sử dụng, vẫn còn trên đầu của initialisation". Đã có một câu hỏi stackoverflow có thể được sử dụng như một tài liệu tham khảo? Chỉ là một ý nghĩ. – gbulmer

+0

Bạn có thể xây dựng một số mã C++ và các lệnh biên dịch không? – ggg

+0

@gbulmer: http://stackoverflow.com/questions/6317796/ctor-init-not-calling-the-global-ctor-instances-in-library và http://stackoverflow.com/questions/9459980/c- global-variable-not-initialized-when-linked-through-static-libraries-nhưng-ok và http://stackoverflow.com/questions/6221947/ensuring-that-a-static-method-gets-called-before- chủ yếu –

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