2012-09-18 28 views
17

Từ C++ 11 dự thảo, 7.5 (para 1.):Extern "C" có hoạt động riêng biệt không?

Hai loại chức năng với ngôn ngữ khác nhau mối liên kết nhiều loại khác nhau ngay cả khi họ là khác giống hệt nhau.

Vì vậy, tôi có thể làm quá tải dựa trên mối liên hệ ngôn ngữ:

extern "C" typedef void (*c_function)(); 
typedef void (*cpp_function)(); 

void call_fun(c_function f) 
{ 
} 
void call_fun(cpp_function f) 
{ 
} 

extern "C" void my_c() 
{ 
} 
void my_cpp() 
{ 
} 
int main() 
{ 
    call_fun(my_c); 
    call_fun(my_cpp); 
} 

Nhưng, với GCC 4.7.1 mẫu mã này sẽ cho các thông báo lỗi:

test.cpp: In function 'void call_fun(cpp_function)': 
test.cpp:7:6: error: redefinition of 'void call_fun(cpp_function)' 
test.cpp:4:6: error: 'void call_fun(c_function)' previously defined here 

Và với Clang ++:

test.cpp:7:6: error: redefinition of 'call_fun' 
void call_fun(cpp_function f) 
    ^
test.cpp:4:6: note: previous definition is here 
void call_fun(c_function f) 
    ^

Bây giờ, đặt câu hỏi:

  • Tôi có hiểu đúng tiêu chuẩn không? Mã này có hợp lệ không?

  • Có ai biết nếu đây là lỗi trong trình biên dịch hoặc nếu chúng cố tình thực hiện theo cách đó cho mục đích tương thích?

+0

Chỉ cần cho các hồ sơ: tiêu chuẩn C++ 03 có chính xác cùng một câu trong đoạn cùng, vì vậy đây không phải là câu hỏi về tính năng C++ 11 chưa được hỗ trợ bởi trình biên dịch. – Gorpik

+0

Xem http://stackoverflow.com/a/10643935/1463922. Hãy chắc chắn rằng các quy ước gọi của C và C++ phù hợp. – PiotrNycz

Trả lời

8

Đó là lỗi đã biết trong gcc và họ ghi lại rằng lỗi không phù hợp vì lỗi này chặn lỗi uber-bug, "sự cố tuân thủ C++ 98".

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

Kiểm tra ngày tạo.

Có một số cuộc thảo luận về phía cuối, về tính thực tiễn của việc giới thiệu bản sửa lỗi. Vì vậy, câu trả lời cho câu hỏi cuối cùng của bạn là "cả hai": đó là lỗi lỗi đã được cố tình để lại cho khả năng tương thích.

Các trình biên dịch khác có cùng vấn đề có thể đã làm lỗi một cách độc lập, nhưng tôi nghĩ nhiều khả năng họ cũng biết rằng nó sai nhưng muốn tương thích với gcc.

+0

Triky, bởi vì tôi thực sự sử dụng con trỏ tới các hàm mẫu được chuyển đổi thành con trỏ tới các hàm 'extern" C "'. Tôi không biết cách nào để tạo ra một hàm mẫu 'extern" C "', vì vậy tôi nghĩ rằng tôi sẽ giữ mã của tôi như bây giờ ... – rodrigo

+0

Mmm, âm thanh tức giận. Tôi đoán bạn có thể làm điều đó với (nhiều nhất) một hàm 'wrapper" C "' cho mỗi C API mà bạn sử dụng, với điều kiện hàm C-linkage lấy một con trỏ dữ liệu người dùng. Bạn buôn lậu con trỏ hàm C++ - liên kết của bạn với hàm liên kết C bằng cách lưu trữ nó trong dữ liệu người dùng và gọi nó từ đó. "Nếu nghi ngờ thêm nhiều sự vô đạo đức", loại điều. –

+0

@Steve_Jessop: Cảm ơn, tôi đã có một cái gì đó như vậy trong tâm trí, nhưng điều đó phá vỡ mục tiêu trên không của tôi mà tôi theo đuổi khi sử dụng các mẫu thay vì một đối tượng điều phối với một chức năng ảo và một thành viên tĩnh func ... _D'oh! _ – rodrigo

10

Mã rõ ràng là hợp lệ. G ++ (và một số trình biên dịch khác) là một bit lỏng (để đặt nó nhẹ) về việc tích hợp liên kết vào loại.

+0

+1 Dựa trên báo giá mà OP cung cấp điều này có vẻ đúng, trừ khi không có một số góc của tiêu chuẩn mà thêm một ngoại lệ cho quote nói. Nhưng hiểu biết James Tôi nghĩ rằng ông biết tốt hơn và tôi tin tưởng từ của mình về điều đó:) –

+1

@Als Ví dụ cổ điển, điều này tạo nên sự khác biệt: chuyển một hàm thành viên tĩnh tới 'pthread_create' (hoặc' CreateThread'). Theo tiêu chuẩn, điều này là bất hợp pháp (vì 'pthread_create' yêu cầu một' extern "C" ', và một thành viên không thể là' extern "C" '), nhưng cả g ++ và VC++ cho phép nó. –

+0

Cảm ơn. Vấn đề là tôi có một số mã xảy ra dựa vào hành vi GCC này.Nó hoạt động, tất nhiên, nhưng nó làm cho tôi một chút khó chịu bởi vì nó có vẻ là hoàn toàn không di động. Vấn đề của tôi là liệu sự lỏng lẻo này có chủ ý không, và do đó tôi có thể coi nó là một "phần mở rộng GCC". – rodrigo

1

Đối với những gì nó có giá trị, mã này cũng thất bại trong việc biên dịch với các thiết lập mặc định trong VS2012:

(8) error C2084: function 'void call_fun(c_function)' already has a body 
(4) see previous definition of 'call_fun' 
(19) error C3861: 'call_fun': identifier not found 
(20) error C3861: 'call_fun': identifier not found 
+0

Nhưng [Trình biên dịch Coumeau C++ trực tuyến] (http://www.comeaucomputing.com/tryitout/) chấp nhận nó mà không có bất kỳ cảnh báo nào! – rodrigo