Нужен ли внешний блок "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?