2011-11-03 44 views
5

Tôi biết cách sử dụng extern "C" nhưng điều kiện nào khi bạn phải sử dụng?Khi nào sử dụng "C" bên ngoài?

extern "C" yêu cầu trình biên dịch C++ không thực hiện bất kỳ tên mangling nào trên dấu ngoặc đơn. Điều này cho phép bạn gọi hàm C từ trong C++.

Ví dụ:

#include <string.h> 

int main() 
{ 
    char s[] = "Hello"; 
    char d[6]; 

    strcpy_s(d, s); 
} 

Trong khi điều này biên dịch tốt trên VC++. Nhưng đôi khi điều này được viết là:

extern "C" { 
#include <string.h> 
} 

Tôi không thấy điểm. Bạn có thể đưa ra ví dụ thực sự khi cần extern "C" không?

+7

Thay vì hack ' 'để tránh tên mangling, sử dụng tiêu đề ''. –

+0

@AlexandreC .: hoàn toàn không phải là ý tưởng hay khi sử dụng tiêu đề ''. Một tiêu đề '' là * không * được bảo đảm để đặt định danh trong không gian tên chung, do đó phá vỡ mã dựa trên các định danh vùng tên chung khi mã đó được chuyển đến một trình biên dịch khác. Ngoài ra, một tiêu đề '' có thể và trong thực tế sẽ đặt định danh trong không gian tên chung, do đó trong lý thuyết cũng phá vỡ mã dựa trên một không gian tên không bị ô nhiễm toàn cầu. "Về lý thuyết" là quá mơ hồ mặc dù; ít nhất một thằng ngốc đã làm điều đó. Vì vậy, không sử dụng chúng. –

+0

@ AlfP.Steinbach: Nếu bạn viết C++, hãy sử dụng ''. Nếu bạn viết C, hãy sử dụng '' và ** biên dịch mã của bạn bằng trình biên dịch C **.Trộn các ngôn ngữ là * không * một ý tưởng hay. –

Trả lời

4

Sử dụng rất phổ biến extern "C" khi bạn xuất một hàm từ thư viện. Nếu bạn không vô hiệu hóa tên C++ mangling bạn có thể làm cho nó rất khó cho khách hàng của thư viện của bạn để đặt tên cho chức năng của bạn. Và tương tự như vậy, khi đi theo một hướng khác, khi bạn đang nhập một hàm đã được xuất với liên kết C.

6

Bạn sử dụng extern "C" để ngăn chặn việc mang tên trong các tệp tiêu đề và tệp đối tượng C++ cho các thư viện hoặc đối tượng đã được biên dịch mà không manglingling.

Ví dụ: giả sử bạn có thư viện widget được biên dịch bằng trình biên dịch C để giao diện được xuất bản của nó không bị cắt xén.

Nếu bạn bao gồm tệp tiêu đề giống như mã của bạn, nó sẽ giả định tên bị xáo trộn và các phiên bản bị xáo trộn là những gì bạn sẽ yêu cầu trình liên kết tìm kiếm.

Tuy nhiên, vì bạn sẽ yêu cầu một cái gì đó như [email protected]_float_charptr và thư viện widget sẽ chỉ xuất bản function, bạn sẽ gặp sự cố.

Tuy nhiên, nếu bạn bao gồm nó với:

extern "C" { 
    #include "widget.h" 
} 

trình biên dịch của bạn sẽ biết rằng nó nên cố gắng sử dụng function, phiên bản không đọc sai.

Đó là lý do tại sao, trong các tập tin tiêu đề cho C thứ có nghĩa là để được bao gồm trong chương trình C _or C++, bạn sẽ thấy những thứ như:

#ifdef __cplusplus 
    extern "C" { 
#endif 

// Everything here works for both C and C++ compilers. 

#ifdef __cplusplus 
    } 
#endif 

Nếu bạn sử dụng một trình biên dịch C để bao gồm này, #ifdef dòng sẽ làm cho các công cụ extern "C" biến mất. Đối với trình biên dịch C++ (trong đó __cplusplus được xác định), mọi thứ sẽ không bị xáo trộn.

+0

tại sao lại có '#ifdef __cplusplus' thứ hai cho? – user103214

+0

@ user974191: nó dành cho cú đúp đóng, nếu không niềng răng sẽ không cân bằng. – paxdiablo

1

Khi bạn liên kết với các thư viện được viết bằng C extern yêu cầu trình biên dịch không trang trí các tên sao cho trình liên kết có thể tìm thấy các hàm. Trong tên hàm C++ et al có thông tin cho trình liên kết, ví dụ: loại đối số và kích thước chứa trong tên.

1

Nếu bạn đang tạo một thư viện nhị phân A, hàm này cho thấy hàm mà bạn muốn gọi từ nhị phân B.

Hãy tưởng tượng A là A.dll và B là B.exe và bạn đang sử dụng hệ thống Windows.

C++ không mô tả bố cục nhị phân sao cho B biết cách gọi A. Thông thường vấn đề này được giải quyết bằng cách sử dụng trình biên dịch tương tự để tạo A và B. Nếu bạn muốn một giải pháp chung chung hơn bạn sử dụng từ khóa extern. Điều này cho thấy hàm theo cách C. C mô tả một định dạng nhị phân sao cho các tệp nhị phân khác nhau từ các trình biên dịch khác nhau có thể nói chuyện với nhau.

Xem: http://en.wikipedia.org/wiki/Application_binary_interface http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B

1

Nếu, trong C++, bạn #include một tiêu đề cho một thư viện bên ngoài (mã hóa trong C) và nếu các chức năng có không tuyên bố extern "C" nó không làm việc (bạn sẽ nhận được tham chiếu không xác định tại thời gian liên kết).

Nhưng những ngày này, người ta mã hóa thư viện C và cung cấp các tập tin tiêu đề cho bạn có xu hướng để biết rằng, và thường đặt extern "C" trong tập tin tiêu đề của họ (phù hợp bảo vệ với #ifdef __cplusplus)

Có lẽ một cách tốt hơn để hiểu là sử dụng (giả sử bạn có một hệ thống Linux) tiện ích nm để hiển thị cho bạn các tên (chưa được sắp xếp) được sử dụng trong một thư viện hoặc một tệp thực thi.

3

Dưới đây là ví dụ cụ thể về nơi mọi thứ bị hỏng và cần extern "C" để được khắc phục.

module.h:

int f(int arg); 

module.c:

int f(int arg) { 
    return arg + 1; 
} 

main.cpp:

#include "module.h" 

int main() { 
    f(42); 
} 

Vì tôi đang trộn C và C++, điều này sẽ không liên kết (của hai tệp đối tượng, chỉ có một cái sẽ biết f dưới tên xén C++ của nó).

Có lẽ cách sạch nhất để sửa lỗi này là bằng cách làm cho các tập tin tiêu đề tương thích với cả C và C++:

module.h:

#ifdef __cplusplus 
    extern "C" { 
#endif 

int f(int arg); 

#ifdef __cplusplus 
    } 
#endif 
+0

+1 điều này giải thích những gì tôi đang tìm kiếm. – user103214

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