Нужен ли внешний блок "C" для включения стандартных заголовков C? - PullRequest
11 голосов
/ 11 ноября 2011

Нужен ли блок extern "C" {} для включения стандартных заголовков C в программу на C ++. Рассматривайте только стандартные заголовки C, которые не имеют аналогов в C ++.

Например:

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

Ответы [ 6 ]

14 голосов
/ 11 ноября 2011

Заголовки системы C обычно уже содержат блок extern "C", защищенный #ifdef __cplusplus.Таким образом, функции автоматически объявляются как extern "C" при компиляции в C ++, и вам не нужно делать это вручную.

Например, в моей системе unistd.h и fcntl.h начинаются с __BEGIN_DECLS иоканчивается на __END_DECLS, которые являются макросами, определенными в 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
8 голосов
/ 11 ноября 2011

Поведение <fcntl.h> и <unistd.h> в C ++ не определено стандартом (поскольку они также не являются частью стандарта C89). Тем не менее, я никогда не видел платформу, где они (а) существуют и (б) действительно должны быть заключены в блок extern "C".

Поведение <stdio.h>, <math.h> и других стандартных заголовков C определено в разделе D.5 стандарта C ++ 03. Им не требуется блок-оболочка extern "C", и они сбрасывают свои символы в глобальное пространство имен. Тем не менее, все в Приложении D "устарело".

Каноническая форма C ++ этих заголовков - <cstdio>, <cmath> и т. Д., И они определены в разделе 17.4.1.2 (3) стандарта C ++, в котором говорится:

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

За исключением случаев, указанных в пунктах 18-27, содержимое каждого заголовка Имя cname должно совпадать с именем соответствующего заголовка name.h, так как указано в ИСО / МЭК 9899: 1990 Языки программирования C (раздел 7), или ISO / IEC: 1990 Языки программирования - C ПОПРАВКА 1: C Целостность, (пункт 7) при необходимости, как будто путем включения. В стандартной библиотеке C ++ однако, объявления и определения (за исключением имен, которые определенные как макросы в C) находятся в области имен (3.3.5) Пространство имен.

Таким образом, стандартный, не осуждаемый, канонический способ использования (например) printf в C ++ - это #include <cstdio>, а затем вызывать std::printf.

2 голосов
/ 11 ноября 2011

Да, вы делаете. Однако многие системы (особенно Linux) уже добавляют брекетинг extern "C", как и вы. См. (В Linux) файлы /usr/include/unistd.h /usr/include/features.h и макрос __BEGIN_DECLS, определенные в /usr/include/sys/cdefs.h и используемые во многих системах Linux, включающие файлы.

Так что в Linux вы обычно можете избежать extern "C", но это не вредит (и, ИМХО, улучшает читабельность в этом случае).

1 голос
/ 11 ноября 2011

Нет, вы должны использовать заголовки оболочки C ++ (например, как <cstdio>). Они позаботятся обо всем этом для вас.

Если заголовок не имеет их, тогда да, вы захотите обернуть их в extern "C" {}.

ETA: Стоит отметить, что многие реализации будут включать в себя обертку внутри файла .h, как показано ниже, так что вы можете обойтись без того, чтобы делать это самостоятельно.

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif
0 голосов
/ 11 ноября 2011

Я просто дважды проверил stdlib.h для компилятора GNU, и объявления не используют extern "C" в качестве объявлений.

редактировать:

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

То есть, включая старые заголовки, вы будете помещать объявления в std при условии определения _GLIBCPP_USE_NAMESPACES?

0 голосов
/ 11 ноября 2011

Это - это хорошая идея сообщить компилятору, чтобы он мог ожидать код C при компиляции в C ++. Вы также можете обнаружить, что сами заголовочные файлы содержат extern "C" { в качестве охранников.

Например, curses.h в моей системе содержит:

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