2014-10-30 12 views
13

Tôi không thấy bất kỳ nhận xét nào trong tiêu chuẩn ngoại trừ các thứ liên quan đến liên kết.Có phải `extern" C "` là một phần của loại hàm không?

Mặc dù tiêu chuẩn không nói gì về quy ước gọi, quy ước gọi có thể khác nhau giữa C và C++ trong thế giới thực, vì vậy tôi mong rằng các loại hàm C và hàm C++ khác nhau. Nhưng có vẻ như không, đặc biệt là trong GCC.

#include <type_traits> 

extern "C" { 
    int c_func(int); 
} 

int cpp_func(int); 

static_assert(!std::is_same<decltype(c_func), decltype(cpp_func)>::value, 
       "It should not be the same type"); 

static_assert không thành công vì GCC coi các chức năng đó có cùng loại.

  • extern "C" một phần của loại chức năng?
  • Làm cách nào để kiểm tra xem một hàm có sử dụng quy ước gọi điện C hoặc quy ước gọi điện C++ không?
+0

C++ hỗ trợ ví dụ: chức năng quá tải. Hai hàm với các kiểu đối số khác nhau nhưng cùng tên - nó không thể được thực hiện với liên kết C vì tên hàm cần được xâu chuỗi để duy trì duy nhất. – keltar

+0

@ keltar Vâng, bạn nói đúng, và đó không phải là những gì tôi yêu cầu ở đây. Đó là về quy ước gọi điện, chứ không phải tên mangling. Mỗi tài liệu, Q/A về 'extern" c "' Tôi tìm thấy trên internet nói về mangling tên nhưng không phải là quy ước gọi điện. – kukyakya

+1

Vì nó không thể được sử dụng trên các phương thức (và do đó không thể ảnh hưởng đến thiscall) - có, nó chỉ nên vô hiệu hóa mangling mà không sửa đổi quy ước, trừ khi được quy định rõ ràng khác (ví dụ: với lệnh __attribute__' trình biên dịch cụ thể). Cả hai loại bạn so sánh là 'int (*) (int)'. – keltar

Trả lời

16

Tiêu chuẩn làm cho nó rõ ràng rằng ngôn ngữ liên kết thực sự là một tài sản của một hàm loại bản thân:

Tất cả các loại chức năng, tên hàm với mối liên hệ bên ngoài, và tên biến với liên kết bên ngoài có liên kết ngôn ngữ .

Trong trường hợp đó là không đủ rõ ràng, có một lưu ý (tôi nhấn mạnh) mà làm cho ý nghĩa đích rõ ràng:

[Ghi chú: Bởi vì mối liên kết ngôn ngữ là một phần của một loại chức năng, khi gián tiếp thông qua một con trỏ đến hàm C , hàm mà giá trị lvalue kết quả được coi là một hàm C. - cuối note]

Hơn nữa,

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, câu trả lời cho câu hỏi đầu tiên của bạn là:

  • , extern "C" là một phần của các loại của một hàm.

Tuy nhiên, hầu hết các trình biên dịch không phân biệt được giữa các loại hàm có liên kết ngôn ngữ C và C++. Đây là ví dụ một lỗi lâu đời trong GCC (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316; xem danh sách các bản sao). Tôi đã không đọc toàn bộ chuỗi một cách cẩn thận, nhưng có vẻ như rất nhiều mã hiện có sẽ bị hỏng nếu GCC bắt đầu thực thi quy tắc rằng chúng thực sự là các loại khác nhau. Đây có lẽ cũng là lý do tại sao các trình biên dịch khác cũng không phù hợp với tiêu chuẩn.

Cho rằng, câu trả lời cho câu hỏi thứ hai của bạn sẽ có vẻ là:

  • Có lẽ không có cách nào di động để thực hiện việc kiểm tra này tại thời gian biên dịch. Tất nhiên sau khi dịch bạn luôn có thể đi vào và nhìn vào tập tin đối tượng và xem liệu tên đó có bị xáo trộn hay không.

Nhưng theo lý thuyết, xác nhận tĩnh của bạn được cho là hoạt động theo cách bạn nghĩ. Đó không phải là trường hợp trong thực tế.

Phụ Lục:

Nếu sự hiểu biết của tôi về tiêu chuẩn là chính xác, sau đó ví dụ như sau hàm mẫu

template <typename R, typename... A> 
void f(R(*)(A...)); 

không thể được khởi tạo để tạo ra một chức năng mà sẽ chấp nhận một con trỏ tới một hàm với liên kết ngôn ngữ C làm đối số, vì loại R(*)(A...) là "con trỏ đến hàm với liên kết ngôn ngữ C++ tham số các loại A... và trả lại R ".

Nếu trình biên dịch thực sự hoạt động như thế này, thật dễ dàng để xem cách bạn có thể xác định chung một hàm có liên kết ngôn ngữ C hoặc C++ hay không.

Nhưng ví dụ này cũng nên làm cho nó rõ ràng như thế nào xấu hiện có mã sẽ phá vỡ nếu trình biên dịch thực sự làm việc theo cách này.

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