2010-04-08 35 views
34

Nếu tôi hiểu nó một cách chính xác điều này có nghĩaC++ từ khóa bên ngoài trên các chức năng. Tại sao không chỉ bao gồm tệp tiêu đề?

extern void foo(); 

rằng chức năng foo được khai báo trong một đơn vị dịch thuật.

1) Tại sao không chỉ #include tiêu đề mà hàm này được khai báo?

2) Trình liên kết biết vị trí cần tìm hàm tại thời gian liên kết như thế nào?

chỉnh sửa: Có lẽ tôi nên làm rõ rằng tuyên bố trên sau đó được tiếp theo bằng cách sử dụng chức năng

foo(); 

Nó không bao giờ được quy định tại đơn vị dịch này.

Trả lời

26

1) Tệp có thể không có tệp tiêu đề. Nhưng có, nói chung, cho các dự án lớn, bạn nên có một tập tin tiêu đề nếu nhiều đơn vị dịch thuật sẽ sử dụng chức năng đó (không lặp lại chính mình).

2) Trình liên kết tìm kiếm qua tất cả các tệp đối tượng và thư viện mà nó được yêu cầu tìm các hàm và các ký hiệu khác.

+0

Điều này có nghĩa là bạn có thể gọi một hàm mô-đun nội bộ (giả sử nguồn không có sẵn) nếu bạn biết chữ ký của hàm? – user199421

+1

Nếu các chức năng có liên kết bên ngoài, thì có.Tuy nhiên, bạn sẽ không thể gọi các hàm được khai báo trong một không gian tên chưa được đặt tên hoặc được khai báo tĩnh (trừ khi bạn biết trình biên dịch/trình liên kết của bạn mang tên như thế nào). –

2

1) Tôi không biết tại sao tôi cần điều này cho một chức năng. Có thể ai đó khác có thể bước vào.

2) Trình liên kết xác định điều này bằng cách duyệt qua tất cả các tệp đối tượng và kiểm tra các ký hiệu bên trong từng tệp đối tượng. Tôi cho rằng tùy thuộc vào mối liên kết của bạn, thứ tự tìm kiếm chính xác có thể thay đổi.

Đối với tất cả các tệp và thư viện của đối tượng GNU binutils xuất hiện trong dòng lệnh của trình liên kết sau khi đối tượng chứa biểu tượng bị thiếu được tìm kiếm từ trái sang phải và biểu tượng đầu tiên được chọn.

Ví dụ 1:

  • áo - sử dụng foo(), bar()
  • Liba - cung cấp thanh()
  • libb - cung cấp foo()

$> ld ao -la -lb

sẽ cho kết quả tìm kiếm các ký hiệu không xác định. Sau đó ld sẽ đi qua các libs từ trái sang phải để tìm kiếm các ký hiệu này và sẽ tìm thấy thanh trong liba và foo trong libb.

này có thể dẫn đến các vấn đề lạ khi phụ thuộc vòng tròn:

Ví dụ 2:

  • a.o - sử dụng thanh()
  • Liba - cung cấp thanh(), sử dụng foo()
  • libb - cung cấp foo(), sử dụng thanh()

Bây giờ, có một phụ thuộc vòng tròn giữa Liba và libb và liên kết sẽ thất bại:

$> ld ao-la -lb

bởi vì khi tìm kiếm thông qua những biểu tượng không xác định trong libb, ld sẽ xác định rằng không có khác lib bên phải - lb cung cấp biểu tượng này. Điều này có thể được cố định trong ít nhất hai cách:

1) liên kết Liba hai lần: $> ld ao-la-la -lb

2) sử dụng tính năng nhóm ld của $> ld ao --start- group -la -lb --end-group

Trong trường hợp 2), nhóm sẽ thông báo cho ld tìm kiếm tất cả các ký hiệu trong tất cả các lib thuộc nhóm này.

7

Điều đó có nghĩa là không có từ khóa bên ngoài. Các hàm có liên kết bên ngoài theo mặc định, trừ khi bạn khai báo chúng tĩnh.

Sử dụng các mẫu thử chức năng là không sao nhưng rất dễ làm sai. Lỗi liên kết bạn sẽ nhận được không dễ chẩn đoán khi bạn xác định lại việc triển khai hàm. Trình liên kết không biết nơi để tìm, nó là công việc của bạn để cung cấp cho nó một tập tin đối tượng có chứa các định nghĩa chức năng để giữ cho nó hạnh phúc.

11

Không, điều này có nghĩa là chức năng foo được khai báo với liên kết bên ngoài. Liên kết ngoài có nghĩa là tên foo đề cập đến cùng chức năng trong toàn bộ chương trình. Trường hợp hàm được định nghĩa không quan trọng. Nó có thể được định nghĩa trong đơn vị dịch thuật này. Nó có thể được định nghĩa trong đơn vị dịch thuật khác.

Sử dụng từ khóa extern như được hiển thị trong ví dụ của bạn là không cần thiết. Các hàm luôn có liên kết bên ngoài theo mặc định. Trên đây là 100% tương đương với chỉ

void foo(); 

Đối với các mối liên kết, khi mối liên kết liên kết các chương trình với nhau một cách đơn giản trông ở khắp mọi nơi. Nó xem xét tất cả các định nghĩa cho đến khi tìm thấy định nghĩa cho foo.

10

Như những người khác đã nêu, từ khóa extern đã được sử dụng để nêu tên (biến hoặc hàm) có liên kết bên ngoài, có nghĩa là tên đề cập đến cùng một đối tượng trong toàn bộ chương trình. Ngoài ra, đây là mặc định cho các biến và hàm được xác định tại phạm vi tệp, vì vậy việc sử dụng này không cần thiết.

Có một sử dụng các từ khóa extern mà đi như thế này:

extern "C" void foo(); 

này có nghĩa là chức năng foo sẽ được liên kết bằng cách sử dụng công ước C trong liên kết (có lẽ vì đây là một chức năng được xác định trong một thư viện C hoặc là một hàm được gọi bởi các chương trình C).

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