Как нестандартные заголовки c (unistd.h, fcntl.h, & hellip;) работают с c ++ [duplicate]

Эта ошибка также возникает на Android 8+, когда вызывается Service.startForeground (int id, уведомление уведомления) , а id - 0.

id int : Идентификатор этого уведомления в соответствии с NotificationManager.notify (int, Notification); не должно быть 0.

11
задан TooTone 3 August 2015 в 16:14
поделиться

6 ответов

Поведение <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) of стандарт C ++, в котором говорится:

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

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

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

8
ответ дан Nemo 19 August 2018 в 19:10
поделиться

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

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

#ifdef __cplusplus
extern "C" {
...
-1
ответ дан AusCBloke 19 August 2018 в 19:10
поделиться
  • 1
    "сообщите компилятору, что он может ожидать код C при компиляции как C ++" . Это не то, что extern "C" делает. Это не меняет интерпретацию кода. Это даже не относится к коду. Это директива языковой привязки, которая инструктирует компилятор генерировать символы, совместимые с теми, которые линкер ожидает для C. Он делает код C ++ вызываемым из C, но не меняет генерацию кода. – IInspectable 7 September 2016 в 08:50
  • 2
    @Inspectable. Не & quot; инструктирует компилятор генерировать символы, совместимые с теми, которые линкер ожидает от C & quot; подразумевает, что он применяется к коду или, по крайней мере, к вызывающему соглашению кода? Это определенно позволяет компилятору (а также компоновщику) что-то знать. – Tanz87 14 April 2017 в 14:12
  • 3
    @ Tanz87: он не меняет генерацию кода один бит. Сгенерированный объектный код идентичен или отсутствует extern "C". Директива применяется только для обозначения имен символов. Он не имеет отношения к вызовам. – IInspectable 14 April 2017 в 17:56

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

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

2
ответ дан Basile Starynkevitch 19 August 2018 в 19:10
поделиться

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

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

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

#ifdef  __cplusplus
extern "C" {
#endif

#ifdef  __cplusplus
}
#endif
1
ответ дан Rob K 19 August 2018 в 19:10
поделиться
  • 1
    Стоит отметить, что заголовки <cstdio> и т. Д. Технически помещают свои определения в пространство имен std. (Многие реализации также помещают их в пространство имен верхнего уровня, но это не то, что говорит стандарт). – Nemo 11 November 2011 в 01:14

Заголовки системы 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
13
ответ дан sth 19 August 2018 в 19:10
поделиться

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

edit:

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

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

-1
ответ дан strager 19 August 2018 в 19:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: