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

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

Например:

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

7 ответов

Решение

Поведение <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, как указано в ISO/IEC 9899:1990 Языки программирования C (раздел 7) или ISO/IEC: Языки программирования 1990 - C ПОПРАВКА 1: C Целостность (пункт 7), в зависимости от ситуации, как если бы она была включена. Однако в стандартной библиотеке C++ объявления и определения (за исключением имен, которые определены как макросы в C) находятся в пределах области имен (3.3.5) пространства имен std.

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

Заголовки системы 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

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

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

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

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

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

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif

макрос __BEGIN_DECLS, определенный в /usr/include/sys/cdefs.h и используемый во многих включаемых файлах системы Linux.

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

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

#ifdef __cplusplus
extern "C" {
...

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

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

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

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

Другие вопросы по тегам