2011-11-10 17 views
9

Tôi có cần khối extern "C" {} để bao gồm tiêu đề C tiêu chuẩn trong chương trình C++ không. Chỉ xem xét tiêu đề C tiêu chuẩn không có đối tác trong C++.Tôi có cần khối "C" bên ngoài để bao gồm tiêu đề C chuẩn không?

Ví dụ:

extern "C" { 
#include <fcntl.h> 
#include <unistd.h> 
} 
+0

Chỉ tìm thấy câu hỏi này tương tự như câu hỏi của bạn: [Tại sao chúng ta cần bên ngoài "C" {#include } trong C++?] (Http://stackoverflow.com/questions/67894/why-do-we-need -extern-c-include-foo-h-in-c) – AusCBloke

Trả lời

7

Hành vi của <fcntl.h><unistd.h> trong C++ không được chỉ định theo tiêu chuẩn (vì chúng cũng không phải là một phần của tiêu chuẩn C89). Điều đó nói rằng, tôi chưa bao giờ nhìn thấy một nền tảng mà họ (a) tồn tại và (b) thực sự cần phải được bọc trong một khối extern "C".

Hành vi của <stdio.h>, <math.h> và các tiêu đề C chuẩn khác được chỉ định theo phần D.5 của tiêu chuẩn C++ 03. Họ không yêu cầu một khối bao bọc extern "C" và họ đưa biểu tượng của họ vào không gian tên chung. Tuy nhiên, mọi thứ trong Phụ lục D đều "không được chấp nhận".

C++ hình thức kinh điển của những tiêu đề là <cstdio>, <cmath>, vv, và họ được quy định bởi phần 17.4.1.2 (3) của chuẩn C++, mà nói:

<cassert> <ciso646> <csetjmp> <cstdio> <ctime> <cctype> <climits> 
<csignal> <cstdlib> <cwchar> <cerrno> <clocale> <cstdarg> <cstring> 
<cwctype> 

Trừ khi ghi chú trong các điều từ 18 đến 27, nội dung của mỗi tiêu đề cname phải giống với tên của tiêu đề tương ứng.h, như được quy định trong ISO/IEC 9899: Ngôn ngữ lập trình 1990 C (khoản 7) hoặc ISO/Ngôn ngữ lập trình IEC: 1990-C SỬA ĐỔI 1: Tính toàn vẹn C, (Khoản 7), như ap sở hữu, như thể bao gồm. Tuy nhiên, trong Thư viện chuẩn C++, , các khai báo và định nghĩa (ngoại trừ các tên là được định nghĩa là macro trong C) nằm trong phạm vi không gian tên (3.3.5) của không gian tên .

Vì vậy, tiêu chuẩn, không bị phản đối, cách kinh điển để sử dụng (ví dụ) printf trong C++ là #include <cstdio> và sau đó gọi std::printf.

1

Không, bạn nên sử dụng các tiêu đề wrapper C++ (ví dụ như <cstdio>). Những người chăm sóc của tất cả những điều đó cho bạn.

Nếu đó là tiêu đề không có, thì có, bạn sẽ muốn bọc chúng trong extern "C" {}.

ETA: Cần lưu ý rằng nhiều triển khai sẽ bao gồm trình bao bọc bên trong tệp .h như dưới đây để bạn có thể tự mình không tự mình làm.

#ifdef __cplusplus 
extern "C" { 
#endif 

#ifdef __cplusplus 
} 
#endif 
+0

Đáng chú ý rằng các tiêu đề '' vv về mặt kỹ thuật đặt định nghĩa của chúng trong không gian tên 'std'. (Nhiều triển khai cũng đặt chúng trong không gian tên cấp cao nhất, nhưng đó không phải là những gì tiêu chuẩn nói.) – Nemo

-1

một ý tưởng tốt để cho trình biên dịch biết để nó có thể mong đợi mã C khi biên dịch như C++. Bạn cũng có thể thấy rằng các tập tin tiêu đề tự chứa extern "C" { làm bảo vệ.

Ví dụ, curses.h trên hệ thống của tôi chứa:

#ifdef __cplusplus 
extern "C" { 
... 
+0

* "cho trình biên dịch biết để nó có thể mong đợi mã C khi biên dịch như C++" * - Đó không phải là những gì 'extern" C "'. Nó không thay đổi cách giải thích mã. Nó thậm chí không áp dụng cho mã. Đó là một chỉ thị liên kết ngôn ngữ hướng dẫn trình biên dịch tạo ra các biểu tượng tương thích với các trình liên kết mong đợi cho C. Nó làm cho mã C++ có thể gọi được từ C, nhưng không thay đổi việc tạo mã. – IInspectable

+0

@IInspectable Không _ "hướng dẫn trình biên dịch tạo các biểu tượng tương thích với các trình liên kết mong đợi cho C" _ ngụ ý rằng nó áp dụng cho mã, hoặc ít nhất là quy ước gọi mã? Nó chắc chắn là để cho trình biên dịch (cũng như trình liên kết) biết điều gì đó. – Tanz87

+0

@ Tanz87: Nó không thay đổi thế hệ mã một chút. Mã đối tượng được tạo giống hệt hoặc không có 'extern" C "'. Chỉ thị này chỉ áp dụng cho việc đặt tên biểu tượng. Nó không có liên quan đến các quy ước gọi điện. – IInspectable

1

Vâng, bạn làm. Tuy nhiên, nhiều hệ thống (đặc biệt là Linux) đã thêm một giá trị extern "C" như bạn làm. Xem các tập tin (trên Linux) /usr/include/unistd.h/usr/include/features.h và macro __BEGIN_DECLS được xác định trong /usr/include/sys/cdefs.h và được sử dụng trong nhiều hệ thống Linux bao gồm các tệp.

Vì vậy, trên Linux, bạn thường có thể tránh extern "C" nhưng không gây hại (và, IMHO, cải thiện khả năng đọc trong trường hợp đó).

11

Các tiêu đề C hệ thống thường đã bao gồm khối extern "C", được bảo vệ bởi #ifdef __cplusplus. Bằng cách này, các hàm tự động được khai báo là extern "C" khi được biên dịch dưới dạng C++ và bạn không cần thực hiện điều đó theo cách thủ công.

Ví dụ trên hệ thống của tôi unistd.hfcntl.h bắt đầu với __BEGIN_DECLS và kết thúc bằng __END_DECLS, đó là macro được định nghĩa trong sys/cdefs.h:

/* C++ needs to know that types and declarations are C, not C++. */ 
#ifdef __cplusplus 
# define __BEGIN_DECLS extern "C" {            
# define __END_DECLS } 
#else 
# define __BEGIN_DECLS 
# define __END_DECLS 
#endif 
2

Theo tôi đó là bổn phận của tập tin tiêu đề xuất sử dụng extern "C " thích hợp.

0

Tôi vừa kiểm tra kỹ stdlib.h đối với trình biên dịch GNU và các khai báo không sử dụng extern "C" làm khai báo.

chỉnh sửa:

if defined __cplusplus && defined _GLIBCPP_USE_NAMESPACES 
define __BEGIN_NAMESPACE_STD namespace std { 

Vì vậy, bao gồm các tiêu đề cũ sẽ đặt tờ khai trên std cung cấp _GLIBCPP_USE_NAMESPACES được xác định?