21

Каково влияние extern "C" в C++?

11

Проблема заключается в том, что неясно, какую роль играет конструкция <code>extern "C"</code> в коде на C++.

Например, я могу привести следующий фрагмент кода:

extern "C" {
   void foo();
}

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

5 ответ(ов)

4

Вы правильно заметили, что использование блоков #ifdef __cplusplus в заголовках C позволяет обеспечить совместимость с C++ кодом. Вот краткое объяснение того, как это работает:

#ifdef __cplusplus
extern "C" {
#endif

// ваш код на C здесь

#ifdef __cplusplus
}
#endif

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

С другой стороны, в C-коде, где __cplusplus не определён, этот блок просто игнорируется, и код будет компилироваться нормально. Это обеспечивает совместимость как с C++, так и с C.

Что касается использования конструкции:

extern "C" {
#include "legacy_C_header.h"
}

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

Какой из этих методов лучше, на самом деле зависит от вашего конкретного случая использования and предпочтений вашей команды. Оба варианта имеют право на существование, и выбор может зависеть от стиля кодирования или требований проекта.

2

В каждом C++-программе все нестатические функции представлены в бинарном файле в виде символов. Эти символы — это специальные текстовые строки, которые уникально идентифицируют функцию в программе.

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

Поскольку C++ позволяет перегрузку функций и имеет много особенностей, которых нет в C (например, классы, методы, спецификации исключений), просто использовать имя функции в качестве имени символа не получится. Для решения этой проблемы в C++ используется так называемое именование с манглингом (name mangling), которое преобразует имя функции и всю необходимую информацию (например, количество и типы аргументов) в какую-то странно выглядящую строку, обрабатываемую только компилятором и загрузчиком.

Таким образом, если вы указываете функцию как extern "C", компилятор не выполняет манглинг имени, и к ней можно обратиться напрямую, используя ее имя символа как имя функции.

Это удобно при использовании dlsym() и dlopen() для вызова таких функций.

0

Не каждый C-заголовок можно сделать совместимым с C++, просто обернув его в extern "C". Если идентификаторы в C-заголовке конфликтуют с ключевыми словами C++, компилятор C++ выдаст ошибку.

Например, я видел, как следующий код не срабатывал в g++:

extern "C" {
struct method {
    int virtual;
};
}

В этом случае это имеет смысл, но стоит иметь в виду, когда вы переносите C-код в C++.

0

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

0

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь