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

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

например:

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

6 ответов


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

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

канонической формой c++ этих заголовков является <cstdio>, <cmath>, etc., и они указаны в разделе 17.4.1.2 (3) стандарта C++, в котором говорится:

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

за исключением случаев, указанных в пунктах 18-27, содержимое каждого заголовка cname должен совпадать с именем соответствующего заголовка.h, как указанных в стандарте ISO / IEC 9899: 1990 языки программирования C (пункт 7), или ISO / IEC: 1990 Языки программирования-C поправка 1: C целостность, (пункт 7), по мере необходимости, как бы путем включения. В стандартной библиотеке C++ , однако объявления и определения (за исключением имен, которые определенные как макросы в C) находятся в области пространства имен (3.3.5) пространства имен std.

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


заголовки system C обычно уже включают a 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" {}.

ЕТА: стоит отметить, что многие реализации будут включать обертку внутри .H-файл, как показано ниже, так что вы можете уйти с делать это самостоятельно.

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif

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

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

#ifdef __cplusplus
extern "C" {
...

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

изменить:

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

Так как старая заголовки будут размещать объявления о предоставляемых _GLIBCPP_USE_NAMESPACES СТД определяется?