Каково влияние extern "C" в C++?
Проблема заключается в том, что неясно, какую роль играет конструкция <code>extern "C"</code>
в коде на C++.
Например, я могу привести следующий фрагмент кода:
extern "C" {
void foo();
}
Ожидается, что ответ на вопрос о том, что делает эта конструкция, поможет мне лучше понять, как интерфейсы C и C++ взаимодействуют друг с другом.
5 ответ(ов)
Вы правильно заметили, что использование блоков #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 предпочтений вашей команды. Оба варианта имеют право на существование, и выбор может зависеть от стиля кодирования или требований проекта.
В каждом C++-программе все нестатические функции представлены в бинарном файле в виде символов. Эти символы — это специальные текстовые строки, которые уникально идентифицируют функцию в программе.
В C имя символа совпадает с именем функции. Это возможно, потому что в C не может быть двух нестатических функций с одинаковым именем.
Поскольку C++ позволяет перегрузку функций и имеет много особенностей, которых нет в C (например, классы, методы, спецификации исключений), просто использовать имя функции в качестве имени символа не получится. Для решения этой проблемы в C++ используется так называемое именование с манглингом (name mangling), которое преобразует имя функции и всю необходимую информацию (например, количество и типы аргументов) в какую-то странно выглядящую строку, обрабатываемую только компилятором и загрузчиком.
Таким образом, если вы указываете функцию как extern "C"
, компилятор не выполняет манглинг имени, и к ней можно обратиться напрямую, используя ее имя символа как имя функции.
Это удобно при использовании dlsym()
и dlopen()
для вызова таких функций.
Не каждый C-заголовок можно сделать совместимым с C++, просто обернув его в extern "C"
. Если идентификаторы в C-заголовке конфликтуют с ключевыми словами C++, компилятор C++ выдаст ошибку.
Например, я видел, как следующий код не срабатывал в g++
:
extern "C" {
struct method {
int virtual;
};
}
В этом случае это имеет смысл, но стоит иметь в виду, когда вы переносите C-код в C++.
Это сообщает компилятору C++, что при линковке следует искать имена этих функций в стиле C, потому что имена функций, скомпилированные в C и C++, различаются на этапе линковки.
extern "C"
предназначен для распознавания компилятором C++ и сообщает компилятору, что указанная функция компилируется (или будет компилироваться) в стиле C. Это нужно для того, чтобы при линковке было связано правильное определение функции из C.
В чем разница между #include <filename> и #include "filename"?
Как изменить цвет вывода echo в Linux
Разница между const int*, const int * const и int * const?
Является ли < быстрее, чем <=?
Что такое "кэш-дружественный" код?