Каков Эффект Объявления 'экстерна “C”' в Заголовке к C++ Общая Библиотека?

На основе этого вопроса я понимаю цель конструкции в соединении библиотек C с кодом C++. Теперь предположите следующее:

У меня есть '.so', совместно использовал библиотеку, скомпилированную с компилятором C++. Заголовок имеет 'определение типа stuct' и много объявлений функции. Если заголовок включает экстерна "C" объявление...

#ifdef __cplusplus
extern "C"
{
#endif

  // typedef struct ...;
  // function decls

#ifdef __cplusplus
}
#endif

... каков эффект? Конкретно я задаюсь вопросом, существуют ли какие-либо вредные побочные эффекты того объявления, так как общая библиотека компилируется как C++, не C.

Там какая-либо причина состоит в том, чтобы иметь экстерна "C" объявление в этом случае?

6
задан Community 23 May 2017 в 11:59
поделиться

5 ответов

Это важно, чтобы компилятор не называл mangle. C ++ использует изменение имен, чтобы различать функции с перегрузками операторов.

Запустите "/ usr / bin / nm" для двоичного файла, чтобы увидеть, что C ++ делает с вашими именами функций: _ ZSt8_DestroyIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEiEvT_S7_SaIT0_E

extern "C" предотвращает искажение этого имени.

IIRC, что позволяет программе динамически связывать символы во время выполнения. Это обычное явление для архитектур типа "плагин".

12
ответ дан 8 December 2019 в 12:19
поделиться

При компиляции C++ имя метода изменяется (mangling) - и вы не сможете вызвать этот метод из другой dll/exe, использующей C.

Чтобы сохранить имя класса и метода, вам нужно компилировать их как "C" без изменения имени.

Библиотека по-прежнему является библиотекой C++, но она раскрывает некоторые свои объявления (те, что в блоке extern "c") как методы C.

4
ответ дан 8 December 2019 в 12:19
поделиться

Одним из недостатков использования extern "C" для C ++ API является то, что он предотвращает перегрузку функций:

extern "C"
{
    // ILLEGAL - C linkage does not support function overloading
    void foo(int x);
    void foo(const char *str);
}
0
ответ дан 8 December 2019 в 12:19
поделиться

#ifdef в примере означает, что только компилятор C ++ увидит extern , обертывающий файл заголовка, что будет означать, что он будет создавать имена без искажений. Компилятор C не видит extern (который он не понимает), но всегда создает неискаженные имена.

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

Не должно быть никаких последствий ни для статического связывания, ни для связывания с разделяемой библиотекой.

0
ответ дан 8 December 2019 в 12:19
поделиться

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

3
ответ дан 8 December 2019 в 12:19
поделиться