Điều này là do tên mangling được thực hiện bởi C++.
extern "C" vs không extern "C"
Như một ví dụ ở đây là những gì CFF Explorer lãm cho bảng xuất khẩu của một dll. Việc đầu tiên được xây dựng với trình biên dịch C++ của borland. Thứ hai được xây dựng với msvc.
Ordinal FunctionRVA Name RVA Name
00000001 0020E140 0032C2B6 createDevice
00000002 0020E244 0032C2C3 createDeviceEx
0000000D 00328DA4 0032C0C1 @[email protected]@IdentityMatrix
0000000E 00328DE4 0032C28A @[email protected]@IdentityMaterial
0000000C 000F9C80 001EE1B6 createDevice
0000000D 000F9CE0 001EE1C3 createDeviceEx
00000001 00207458 001EDDC7 [email protected]@[email protected]@[email protected]@A
00000002 001F55A0 001EDDF5 [email protected]@[email protected]@[email protected]@[email protected]
2 chức năng đầu tiên createDevice
và createDeviceEx
chứa chữ ký extern "C"
trong nguyên mẫu của nó trong khi những người khác thì không. Chú ý sự khác biệt trong mã hóa khi sử dụng C++ mangling. Sự khác biệt thực sự là sâu hơn hơn thế.
ABI & Tiêu chuẩn
Như đã giải thích trong câu trả lời khác, tiêu chuẩn C++ không không định một MộtbstractBinarytôinterface. Điều đó có nghĩa là các nhà cung cấp thiết kế các công cụ của họ có thể làm bất cứ điều gì họ muốn khi nói đến các cuộc gọi chức năng được xử lý như thế nào và quá tải hoạt động như thế nào - miễn là nó thể hiện hành vi mong đợi theo tiêu chuẩn.
Với tất cả các lược đồ mã hóa khác nhau, không có cách nào ngôn ngữ khác có thể có hy vọng làm việc với các mô-đun được biên dịch bằng C++. Các mô-đun Heck được biên dịch với một trình biên dịch C++ không thể làm việc với trình biên dịch khác! Các nhà cung cấp trình biên dịch được tự do thay đổi mã hóa giữa các phiên bản theo quyết định của họ.
Ngoài ra, không có ABI chung có nghĩa là không có cách nào dự kiến phổ biến để gọi vào các chức năng/phương pháp này. Ví dụ, một trình biên dịch có thể vượt qua các đối số của nó trên ngăn xếp trong khi trình biên dịch khác có thể truyền nó trên thanh ghi. Người ta có thể vượt qua các đối số từ trái sang phải trong khi một đối số khác có thể được đảo ngược. Nếu chỉ một trong những khía cạnh này không khớp chính xác giữa người gọi và callee thì ứng dụng của bạn sẽ bị lỗi ... đó là nếu bạn may mắn. Thay vì đối phó với điều này, các nhà cung cấp chỉ đơn giản nói không bằng cách buộc một lỗi xây dựng với các mã hóa khác nhau.
OTOH, trong khi C không có ABI chuẩn hóa, C là ngôn ngữ đơn giản hơn nhiều để giải quyết bằng cách so sánh. Hầu hết các nhà cung cấp trình biên dịch C xử lý trang trí chức năng và cơ chế gọi theo cách tương tự. Kết quả là có một loại tiêu chuẩn 'không thực tế' ngay cả khi ABI không được chỉ định rõ ràng trong tiêu chuẩn. Với tính phổ biến này, nó giúp dễ dàng hơn cho các ngôn ngữ khác giao tiếp với các mô-đun được biên dịch bằng C.
Ví dụ, trang trí __stdcall
được ký theo một quy ước cuộc gọi cụ thể. Đối số được đẩy sang phải sang trái và callee có trách nhiệm làm sạch ngăn xếp sau đó. __cdecl
tương tự nhưng được hiểu rằng người gọi gọi có trách nhiệm làm sạch ngăn xếp.
Các bottomline
Nếu module trong câu hỏi phải tương thích với các ngôn ngữ bên ngoài của C++, trang trí nó một cách thích hợp và phơi bày nó như là một C API là đặt cược tốt nhất của bạn. Lưu ý rằng bạn đang từ bỏ một số tính linh hoạt bằng cách thực hiện việc này. Đặc biệt, bạn sẽ không thể quá tải các chức năng đó vì trình biên dịch không còn có thể tạo ra các ký hiệu duy nhất cho mỗi quá tải với tên mangling.
Nếu khả năng tương tác không quan trọng đối với mô-đun được đề cập - nó chỉ được sử dụng với cùng công cụ được tạo, sau đó bỏ qua trang trí extern "C"
từ nguyên mẫu của bạn.
Tôi đã thêm một lời giải thích chi tiết hơn về lý do tại sao nó là cần thiết, nếu bạn quan tâm. – greatwolf